算法设计与分析:大整数的加减乘除运算

news2024/12/24 8:29:07

目录

任务描述

相关知识

大整数的思想

大整数加法

大整数减法

大整数与整数的乘法

大整数乘法

大整数与整数的除法

n的阶乘求解思路

编程要求

测试说明


任务描述

本关任务:掌握大整数的基本思想,并运用大整数的基本运算计算出常规整数n的阶乘,然后统计大整数n!中数字0的个数。

相关知识

为了完成本关任务,你需要掌握:1.大整数的思想,2.大整数加法,3.大整数减法,4.大整数与整数的乘法,5.大整数乘法,6.大整数与整数的除法,7.n的阶乘求解思路。

大整数的思想

大整数的思想:用数组存储大整数(超长整数),为处理简单起见约定每个数组元素存放相同位数(T位)的数字片段(假定T=4位)。

设定一个大小为N的整型数组a[0,1,..,N−1],给定一个大整数998877665544332211,每个数组单元使用T=4位存储,为了方便计算,将大整数的低位存入数组的高维索引,如下图所示:

 

大整数加法

大整数的加法和一般的整数加法是类似的,从低位开始,同位置的数相加,若大于进制K=10000,则进位,以此类推。特别的,当进制K=10时,每个数组单元存储的数字为T=1位,大整数的加法运算就等价于常规整数的加法运算,只不过是用数组来模拟计算过程。

例如两个大整数分别为998877665544332211和112233445566778899,按照T=4,K=10000的参数设定,分别存储在整型数组a和b中,数组大小都是N,它们的加法运算(c=a+b)过程如图所示:

 

大整数减法

同样的,大整数的减法过程与一般的整数减法也是类似的,从低位开始,同位置的数相减,被减数小于减数时,被减数向高位借1,当T=4,K=10000时,借一位相当于加10000。特别的,倘若被减大整数小于减数大整数,则先交换它们,然后再做减法,最后为结果添加负号,为了方便起见,本关卡的测试数据保证被减数大于减数。

对于上面的大整数a=998877665544332211和大整数b=112233445566778899,它们的减法运算(c=a−b)过程如下图所示:

 

大整数与整数的乘法

我们知道整数之间的乘法是逐位相乘,然后相加。对于大整数与整数之间的乘法,则是把“位”扩展成了“块”,即大整数的每个数组单元分别与整数相乘,然后加上进位(初始为0),并把结果放在对应位置上,若超过了进制K,则进位,以此类推。

例如大整数123456789和整数12345,按照T=4,K=10000的参数设定,大整数存储在整型数组d中,数组大小为N,整数存储在整型变量p中,它们的乘法运算(c=d×p)过程如图所示:

 

大整数乘法

我们已经知道了大整数与整数之间的乘法运算,对于大整数a与大整数b的乘法运算则是大整数与整数乘法运算的拓展,也就是说,将大整数a分别与大整数b的每个数组单元相乘,然后放置在相应位置上,并累加进位。

对于上面的大整数a=998877665544332211和大整数b=112233445566778899,它们的乘法运算(c=a×b)过程如下图所示:

 

 

大整数与整数的除法

大整数d与整数p的除法运算保留商和余数,其中商仍然可能是大整数,而余数则是比除数要小的整数。大整数作为被除数,从高位开始,依次(从左到右i=0→N−1)将每个数组单元d[i]除以除数p,当前整除结果作为商存储在数组c对应的高位c[i]中,余数保留到下一个数组单元的计算中,依次类推,最后的余数则是大整数被除尽后的剩余项。

对于上面的大整数d=123456789和整数p=12345,它们的除法运算(c=d/p,r=d过程如下图所示:

 

n的阶乘求解思路

n的阶乘是一个非常大的整数,首先需要运用大整数的基本运算法则求得n!的数值。这一步可以借助大整数与整数的乘法运算,然后循环n−1次乘法即可得到n!。

n!=1×2×3×..×n

其次是统计n!中数字0的个数,因为大整数在数组中是分块存储的,所以有两种统计方式(记n!=M):

  • 借助大整数与整数的除法运算:让M除以10,判断余数r是否为0,若为r=0,则答案累加1,然后将M赋值为商c,即M=c,重复以上步骤,直到M=0,程序结束;

  • 借助大整数在数组中的分块存储方式:循环枚举大整数n!的数组单元,计算每个单元里的整数包含数字0的个数,最后进行累加求和即为答案。注意,每个整数单元里的数值不一定为T=4位,比如M[i]=102,当i不是大整数的头时,M[i]的真实数据为0102,包含两个数字0(一个简单的处理技巧:将M[i]加上K=10000,即M[i]+K=10102,然后判断它所包含的数字0的个数)。

     

    编程要求

    本关的编程任务是补全右侧代码片段calcBeginEnd中间的代码,具体要求如下:

  • calc中,根据大整数的基本运算原理,计算整数n的阶乘,并统计出n!中数字0的个数,然后将统计结果作为函数返回值。

测试说明

平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确,测试数据保证10001>n>0。

以下是平台的测试样例:

测试输入: 10 预期输出: 2

输入格式: 第1行:整数n 输出格式: 第1行:n!中数字0的个数

Tips:注意整数乘法越界的情况

//
//  main.cpp
//  step1
//
//  Created by ljpc on 2018/12/4.
//  Copyright © 2018年 ljpc. All rights reserved.
//

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;

// 最大长度N,分块长度K
const int N = 10001;
const int K = 10000;
const int T = (int)log10(K); // K=10000, T=4

void char_to_int(char *s, int *c)
{
    // *s = 1234567890
    // *c = 0000 .... 0012 3456 7890 (K=10000, T=4, c[0] c[1] .... c[N-2] c[N-1])
    // i  = 0         N-3  N-2  N-1  (c的下标索引i)
    int L = (int)strlen(s);
    for (int i=N-1; i>=0; i--) {
        c[i] = 0;
        if (L>=0) {
            for (int j=0; j<T; j++) {
                if (L-T+j < 0) {
                    continue;
                }
                c[i] = c[i] * 10 + s[L-T+j] - '0';
            }
            L -= T;
        }
    }
}

void output(int *c)
{
    // *c = 0000 .... 0012 3456 7890 (K=10000, T=4, c[0] c[1] .... c[N-2] c[N-1])
    // i  = 0         N-3  N-2  N-1  (c的下标索引i)
    // out= 1234567890
    bool flag = true;
    for (int i=0; i<N; i++) {
        if (flag && c[i]==0) {
            continue;
        }
        if (flag) { // 第一个非0数字:大数的头块
            printf("%d", c[i]);
            flag = false;
        }
        else { // 大数头块之后的 T 数字块
            int TK = K/10;
            int tmp = c[i];
            while (TK) {
                printf("%d", tmp/TK);
                tmp %= TK;
                TK /= 10;
            }
        }
    }
    printf("\n");
}

void add(int *a, int *b, int *c)
{
    int carry = 0;
    for (int i=N-1; i>=0; i--) {
        c[i] = 0;
        c[i] = a[i] + b[i] + carry;
        carry = c[i] / K;
        c[i] = c[i] % K;
    }
    
}

void sub(int *a, int *b, int *c)
{
    int borrow = 0;
    for (int i=N-1; i>=0; i--) {
        c[i] = 0;
        c[i] = a[i] - b[i] - borrow;
        if (c[i] >= 0) {
            borrow = 0;
        }
        else {
            c[i] = c[i] + K;
            borrow = 1;
        }
    }
    
}

void mul1(int *a, int b, int *c)
{
    long long tmp = 0;
    int carry = 0;
    for (int i=N-1; i>=0; i--) {
        tmp = (long long)a[i] * (long long)b + (long long)carry;
        c[i] = (int)(tmp % K);
        carry = (int)(tmp / K);
    }
    
}

void mul2(int *a, int *b, int *c)
{
    long long tmp = 0;
    int carry = 0;
    for (int i=N-1; i>=0; i--) {
        c[i] = 0;
    }
    for (int i=N-1; i>=0; i--) { // b[i]
        carry = 0;
        for (int j=N-1, idc=i; j>=0&&idc>=0; j--, idc--) { // a[j]
            tmp = (long long)a[j] * (long long)b[i] + (long long)carry + (long long)c[idc];
            c[idc] = (int)(tmp % K);
            carry = (int)(tmp / K);
        }
    }
    
}

int div(int *a, int b, int *c)
{
    long long tmp = 0;
    int remain = 0;
    for (int i=0; i<N; i++) {
        tmp = (long long)a[i] + (long long)remain * (long long)K;
        c[i] = (int)(tmp / b);
        remain = (int)(tmp % b);
    }
    return remain;
    
}

int calc(int n)
{
    // 请在这里补充代码,完成本关任务
    /********* Begin *********/
    int a[N] = {0};
    int c[N] = {0};
    a[N-1] = 1;
    for (int i=2; i<=n; i++) {
        mul1(a, i, c);
        for (int j=0; j<N; j++) {
            a[j] = c[j];
            c[j] = 0;
        }
    }
    int tot = 0;
    /*  方法一
    while (1) {
        bool flag = true;
        for (int i=0; i<N; i++) {
            if (a[i]) {
                flag = false;
                break;
            }
        }
        if (flag) {
            break;
        }
        int r = div(a, 10, c);
        if (r==0) {
            tot++;
        }
        // a = 10 * c + r
        for (int j=0; j<N; j++) {
            a[j] = c[j];
            c[j] = 0;
        }
    }
     */
    // 方法二
    int tmp = 0;
    bool flag = true;
    for (int i=0; i<N; i++) {
        if (flag && a[i]==0) {
            continue;
        }
        if (flag) {
            tmp = a[i];
            flag = false;
        }
        else {
            tmp = a[i] + K;
        }
        while (tmp) {
            if (tmp % 10 == 0) {
                tot++;
            }
            tmp /= 10;
        }
    }
    
    return tot;
    
    
 
    /********* End *********/
}

int main(int argc, const char * argv[]) {
    
    int n;
    
    scanf("%d", &n);
    
    int tot = calc(n);
    printf("%d\n", tot);

    return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/514851.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

seaweedfs服务启动参数及翻译(seaweed参数、seaweed命令、weed参数、weed命令)(在单个容器同时启动master、volume、filer服务)

文章目录 weed命令翻译weed server命令翻译 weed filer命令 docker容器运行示例&#xff08;docker run命令&#xff09;以下是一个在单个容器启动master、volume、filer服务的示例 weed server 容器debug 版本&#xff1a;3.47从官方镜像docker容器里扒下来的&#xff0c;只扒…

【多线程】单例模式

目录 饿汉模式 懒汉模式-单线程版 懒汉模式-多线程版 懒汉模式-多线程版(改进) 单例是一种设计模式。 啥是设计模式 ? 设计模式好比象棋中的 " 棋谱 ". 红方当头炮 , 黑方马来跳 . 针对红方的一些走法 , 黑方应招的时候有一些固定的套路. 按照套路来走局势…

5.11 C高级作业

编写一个名为myfirstshell.sh的脚本&#xff0c;它包括以下内容。 1、包含一段注释&#xff0c;列出您的姓名、脚本的名称和编写这个脚本的目的 2、和当前用户说“hello 用户名” 3、显示您的机器名 hostname 4、显示上一级目录中的所有文件的列表 5、显示变量PATH和HOME的…

高性能网络 SIG 月度动态:长期投入得到业界认可,新增一位 virtio reviewer

高性能网络 SIG&#xff08;Special Interest Group&#xff09; &#xff1a;在云计算时代&#xff0c;软硬件高速发展&#xff0c;云原生、微服务等新的应用形态兴起&#xff0c;让更多的数据在进程之间流动&#xff0c;而网络则成为了这些数据流的载体&#xff0c;在整个云时…

Hive概述和安装

hive简介 Hive&#xff1a;由Facebook开源用于解决海量结构化日志的数据统计工具。 Hive是基于Hadoop的一个数据仓库工具&#xff0c;将结构化的数据文件映射为一张表&#xff0c;并提供类SQL(HQL)查询功能。 Hive本质&#xff1a;将HQL转化成MapReduce程序 &#xff08;1&am…

无锁队列实现及使用场景

写在前面 在看无锁队列之前&#xff0c;我们先来看看看队列的操作。队列是一种非常重要的数据结构&#xff0c;其特性是先进先出&#xff08;FIFO&#xff09;&#xff0c;符合流水线业务流程。在进程间通信、网络通信间经常采用队列做缓存&#xff0c;缓解数据处理压力。根据…

device_node转换成platform_device

device_node转换成platform_device 文章目录 device_node转换成platform_device转换规则主要核心函数of_default_bus_match_tablearmarm64of_platform_register_reconfig_notifier Linux内核是如何将device_node转换成platform_deviceof_platform_populate函数处理根节点下的子…

在ubuntu连接Xlight FTP Server

一 在windows上搭建服务器 http://www.xlightftpd.com/download.htm 使用英文版&#xff0c;使防止在ubuntu中登录中文版时&#xff0c;显示乱码 新建用户和用户对应的服务器目录 如下所示&#xff0c;默认只有读权限 全都勾选 勾选完毕后的效果 在目录中放一个文件&#…

10款常用的原型设计工具,包含一键生成原型工具

原型图是产品设计师日常工作的“常客”&#xff0c;原型图软件也扮演着产品设计师的“武器”角色。 许多新产品设计师不知道如何选择原型图软件。本文盘点了10个优秀的原型图软件&#xff0c;让我们来看看。 1.即时设计 即时设计是一款免费的在线 UI 设计工具&#xff0c;无…

【Java数据结构】排序

排序 插入排序希尔排序选择排序堆排序冒泡排序快速排序序列的分割Hoare法挖坑法快慢指针法 优化1 - 三数取中优化2- 数据规模小时的插入 归并排序 插入排序 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的记录按其关键码值的大小逐个插…

Jetson Orin环境安装Opencv+Cuda以及vscode环境配置

文章目录 一&#xff1a;Opencv Cuda源码的下载、编译1.卸载jetson上自带的无cuda加速Opencv2.安装Opencv依赖库3.下载 OpenCV 和 opencv_contrib 源码4.编译安装 OpenCV、opencv_contrib 二&#xff1a;Opencv 的环境配置三&#xff1a;Vscode 中的Opencv环境配置四&#xff…

系统分析师---系统建模相关高频考试知识点

系统规划---成本效益分析 评价信息系统经济效益常用的方法主要有成本效益分析法,投入产出分析法和价值工程方法。盈亏平衡法常用于销售定价; 可行性分析 系统规划是信息系统生命周期的第一个阶段,其任务是对企业的环境、目标以及现有系统的状况进行初步调查,根据企业目标…

张正友相机标定原理

相机标定 记录1.1 张正友相机标定相关 参考 记录 最小二乘法&#xff1a;A^T A x 0 奇异值分解的办法求解最小二乘法 因为可以假设标定板平面在世界坐标系Z0的平面上&#xff0c; 1.1 张正友相机标定相关 单目相机标定实现–张正友标定法(包含具体的实现以及C代码&#xff0…

《花雕学AI》ChatGPT Shortcut Chrome 扩展:让生产力和创造力加倍的 ChatGPT 快捷指令库

你是否想要与一个智能的对话伙伴聊天&#xff0c;或者让它帮你完成各种任务&#xff0c;如写作、编程、摘要、翻译等&#xff1f;如果是的话&#xff0c;你可能会对 ChatGPT 感兴趣。ChatGPT 是一个基于 GPT-3.5 的对话式人工智能&#xff0c;可以与用户进行自然、流畅、有趣的…

文件看不见了,内存还占着容量的找回教程

U盘文件突然不见了但还占用内存空间的解决方法 如果文件看不见了但内存占用仍然存在&#xff0c;可能是因为以下原因&#xff1a; 文件被隐藏。某些操作系统允许隐藏文件&#xff0c;这些文件只能在文件浏览器中被找到。 文件被损坏。如果文件损坏&#xff0c;它可能不会显示在…

Python图形化编程开源项目拼码狮PinMaShi

开源仓库 #项目地址 https://github.com/supercoderlee/pinmashi https://gitee.com/supercoderlee/pinmashiPinMaShi采用electron开发&#xff0c;图形化拖拽式编程有效降低编程难度&#xff0c;对Python编程的初学者非常友好&#xff1b;积木式编程加快Python程序的开发&…

黑马Redis笔记-高级篇

黑马Redis笔记-高级篇 1、Redis持久化&#xff08;解决数据丢失&#xff09;1.1 RDB持久化1.1.1 定义1.1.2 异步持久化bgsave原理 1.2 AOF持久化1.3 RDB和AOF比较 2、Redis主从&#xff08;解决并发问题&#xff09;2.1 搭建主从架构2.2 主从数据同步原理2.2.1 全量同步2.2.2 增…

基于哈里斯鹰算法优化的核极限学习机(KELM)分类算法 -附代码

基于哈里斯鹰算法优化的核极限学习机(KELM)分类算法 文章目录 基于哈里斯鹰算法优化的核极限学习机(KELM)分类算法1.KELM理论基础2.分类问题3.基于哈里斯鹰算法优化的KELM4.测试结果5.Matlab代码 摘要&#xff1a;本文利用哈里斯鹰算法对核极限学习机(KELM)进行优化&#xff0c…

【小梦C嘎嘎——启航篇】基本语法格式:namespace ?

基本语法格式&#xff1a;namespace &#xff1f;&#x1f60e; 前言&#x1f64c;namespace 是什么&#xff1f;namespace 的意义何在&#xff1f; 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&…

springboot + vue 部署 阿里云云服务器 ECS

安装所需文件 安装mysql5.7 下载MySQL的yum源配置 wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm安装MySQL的yum源 yum -y install mysql57-community-release-el7-11.noarch.rpm使用yum方式安装MySQL5.7&#xff08;下载需要点时间&#xf…