蓝桥杯高频考点——高精度(含C++源码)

news2025/5/15 9:57:49

前言

前两天考完了csp认证,总的来说还算正常发挥 休息了两天给大家更一个蓝桥杯

这个高精度是啥东西 说白了就是我们一般的数据类型存储不了的数字进行运算
具体来说就是10…(此处省略500个0),即便是强如 long long 也是存不下的

那么解决办法是啥?不算了?
显然不是 我们可以模拟小学学到竖式来计算 我们来分别来具体看加减乘除

我这里用例题来呈现
具体的讲解视频我附在这里 讲的真的太好了 我感觉就算一点没学过算法也能听明白

高精度系列视频

高精度加法

例题

思路及代码

solution 1(初阶版 40分)

在这里插入图片描述

我的注释写的非常详细了 但是由于我没有对特殊情况做出处理导致才过了2个样例
这里样例比较少 但是大部分情况下代码是没问题的

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s1,s2;
    //对于string类型会自动初始化为空字符串
    //对于数组来说如果不对他初始化 他会是一个随机值
    int a1[110], a2[110], a3[110]={0};
    //最长是500位加上500位 结果最多是一个501位数 所以大小我们定义510肯定够了 a1 a2 a3分别保存逆序存放的数字和结果 
    //读入我们输入的数字存进字符串里面
    cin>>s1;
    cin>>s2;
    
    //将读入的数字逆序存放在数组里面
    //例如我们将123的1存到数组里面 它的位置就是
    //a1[s1.size()-1-0] 
    for(int i=0;i<s1.size();i++)
        {
            a1[s1.size()-i-1]=s1[i]-'0';
            //-i是因为倒序  -1是因为数组下标从0开始;
        }
    for(int i=0;i<s2.size();i++)
        {
            a2[s2.size()-i-1]=s2[i]-'0';
        }
    //求出循环次数也就是我们模拟竖式相加的次数 而在加法中这个是由较大的数来决定的 这里不用考虑负数也就是字符串较长的数字
    int len=s1.size();
    if(s2.size()>s1.size())
    {
        len=s2.size();
    }
    //相加操作
    for(int i=0;i<len;i++)
        {
            a3[i]=a1[i]+a2[i];
        }
    //满10进位
    for(int i=0;i<len;i++)
        {
            if(a3[i]>10)
            {
                a3[i+1]+=a3[i]/10;
                a3[i]=a3[i]%10;
            }
            
        }
    //逆序输出
    //因为我们一开始将数组置为0 所以我们只需要找到第一个不为0的点
    //就可以找到逆序输出的起点
    if(a3[len]!=0)//判断一下最高位置是不是0
    {
        len++;
    }
    for(int i=len-1;i>=0;i--)
        {
            cout<<a3[i];
        }
}

solution 2(完全体 AC)

首先优化的点在于将上面代码中的对应相加和进位操作放在了一个循环里面

第二个就是比较重要的点 就是如果结果是0 我们需要只输出一个0 也就是说去掉前序位置上的所有0

#include <bits/stdc++.h>
using namespace std;

int main() {
    std::ios::sync_with_stdio(false); // 提高输入输出效率
    std::cin.tie(NULL);

    string s1, s2;
    cin >> s1 >> s2;

    int a1[510] = {0}, a2[510] = {0}, a3[510] = {0};

    // 将字符串逆序存入数组
    for(int i = 0; i < s1.size(); i++) {
        a1[s1.size() - i - 1] = s1[i] - '0';
    }
    for(int i = 0; i < s2.size(); i++) {
        a2[s2.size() - i - 1] = s2[i] - '0';
    }

    // 求出最大长度
    int len = max(s1.size(), s2.size());

    // 相加并处理进位
    int carry = 0;
    for(int i = 0; i < len || carry; i++) {
        if(i < len) a3[i] += a1[i] + a2[i];
        if(a3[i] >= 10) {
            carry = a3[i] / 10;
            a3[i] %= 10;
            a3[i+1] += carry;
        } else {
            carry = 0;
        }
    }

    // 输出结果
    int start = len;
    while(start >= 0 && a3[start] == 0) start--;

    if(start == -1) cout << "0"; // 特殊情况:结果为0
    else {
        for(int i = start; i >= 0; i--) {
            cout << a3[i];
        }
    }

    return 0;
}

高精度乘法

例题

在这里插入图片描述
题目链接

思路及代码

solution 1(TLE 但是代码很清晰)


#include <bits/stdc++.h>
using namespace std;
//首先这是一道高精度乘法(而且是高精度乘以高精度)
//我们需要用其中一个数的每一位去乘以另外一个高精度数
//大体上的思路就是用两层循环来实现 内层循环a1外层循环a2
int main()
{
    //string s1=""可以不初始化 string类型默认初始化为空字符串
    string s1,s2;

    int a1[2010],a2[2010],a3[4020]={0};
    getline(cin,s1);
    getline(cin,s2);
    //逆序存放在数组当中
    for(int i=0;i<s1.size();i++)
    {
        a1[i]=s1[s1.size()-i-1]-'0';
    }
    for(int j=0;j<s2.size();j++)
    {
        a2[j]=s2[s2.size()-j-1]-'0';
    }
    for(int i=0;i<s2.size();i++)
    {
        for(int j=0;j<s1.size();j++)
        {
            //第一次a3[j+0]=a3[j+0]+a1[j]*a2[i]
            //第二次a3[j+1]=a3[j+1]+a1[j]*a2[i]
            //通过找规律我们可以知道我们每一轮的变化就是
            a3[j+i]=a3[j+i]+a1[j]*a2[i];
            //进位判断
            if(a3[j+i]>10)
            {
                a3[j+i+1]+=a3[j+i]/10;//看看能进几
                a3[j+i]=a3[j+i]%10;
            }
        }
    }
    //完成相乘操作之后 我们就需要逆序输出一下a3
    //首先我们需要明确的就是一个200✖️200的结果不会超过400位数/
    //也就是这两个长度之和
    int index=0;
    for(int i=s1.size()+s2.size();i>=0;i--)
    {
        if(a3[i]!=0)
        {
            index=i;//找到了起始下标
            break;
        }
    }
    for(int i=index;i>=0;i--)
    {
        cout<<a3[i];
    }

    return 0;



}

solution 1的问题


  1. 算法复杂度问题
  • 当前复杂度:你的代码使用了两层嵌套循环来实现高精度乘法,外层循环遍历 s2 的每一位,内层循环遍历 s1 的每一位。假设 s1s2 的长度分别为 mn,那么时间复杂度为 O(m × n)
  • 问题点:如果输入的字符串长度较大(例如接近 2000),则计算量会非常大,导致超时。

  1. 进位逻辑效率问题
  • 当前实现:在每次相乘后立即进行进位操作:

    if(a3[j+i] > 10) {
        a3[j+i+1] += a3[j+i] / 10;
        a3[j+i] = a3[j+i] % 10;
    }
    

    这种方式会在每次相乘后都检查是否需要进位,增加了不必要的开销。

  • 优化方法:可以先完成所有乘法操作,最后统一处理进位。这样可以减少重复的进位判断。


  1. 输出部分的效率问题
  • 当前实现

    for(int i = s1.size() + s2.size(); i >= 0; i--) {
        if(a3[i] != 0) {
            index = i; // 找到起始下标
            break;
        }
    }
    for(int i = index; i >= 0; i--) {
        cout << a3[i];
    }
    

    使用了两个循环来找到第一个非零位并逆序输出结果。

  • 优化方法:可以通过一次循环完成查找和输出,减少冗余操作。


  1. 输入方式的问题
  • 当前实现

    getline(cin, s1);
    getline(cin, s2);
    

    使用 getline 读取输入字符串,虽然功能正确,但在某些评测环境中可能会比 cin 稍慢。

  • 优化方法:如果输入不包含空格,可以直接使用 cin 提高效率。


solution 2(优化 AC)

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false); // 不用管就是 提高输入输出效率
    cin.tie(NULL);

    string s1, s2;
    cin >> s1 >> s2; // 使用 cin 提高效率

    int a1[2010] = {0}, a2[2010] = {0}, a3[4020] = {0};

    // 将字符串逆序存入数组
    for(int i = 0; i < s1.size(); i++) {
        a1[i] = s1[s1.size() - i - 1] - '0';
    }
    for(int i = 0; i < s2.size(); i++) {
        a2[i] = s2[s2.size() - i - 1] - '0';
    }

    // 高精度乘法
    for(int i = 0; i < s2.size(); i++) {
        for(int j = 0; j < s1.size(); j++) {
            a3[i + j] += a1[j] * a2[i]; // 先累加结果
        }
    }

    // 统一处理进位
    for(int i = 0; i < s1.size() + s2.size(); i++) {
        if(a3[i] >= 10) {
            a3[i + 1] += a3[i] / 10;
            a3[i] %= 10;
        }
    }

    // 输出结果
    int start = s1.size() + s2.size();
    while(start > 0 && a3[start] == 0) start--; // 去掉前导零

    if(start == -1) cout << "0"; // 特殊情况:结果为0
    else {
        for(int i = start; i >= 0; i--) {
            cout << a3[i];
        }
    }

    return 0;
}

高精度减法

例题

在这里插入图片描述

题目链接

代码及思路

solution 1 (90分)

应该是对于结果正好为0的时候没有特判 补一下

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s1,s2;
    cin>>s1;
    cin>>s2;
    int a1[10100],a2[10100],a3[10100]={0};
    char flag ='+';
    //保证始终都是位数长的减去小的
    //比如现在让你求10-200 我们可以算200-10 然后在结果前面加上负号
    //如果这个flag是正的则不需要输出
    if(s1.size()<s2.size()||(s1.size()==s2.size()&& s1<s2))
    {
        swap(s1,s2);
        flag='-';
    }
    //逆序存储
    for(int i=0;i<=s1.size();i++)
    {
        a1[s1.size()-i-1]=s1[i]-'0';
    }
    for(int i=0;i<=s2.size();i++)
    {
        a2[s2.size()-i-1]=s2[i]-'0';
    }
    for(int i=0;i<s1.size();i++)
    {
        //先借好位
        if(a1[i]<a2[i])//需要借位的情况
        {
            a1[i]+=10;
            a1[i+1]--;
        }
        //再对应相减
        a3[i]=a1[i]-a2[i];
    }
    if(flag=='-')
    {
        cout<<flag;
    }
    int index=0;//找到倒序输出的起始位置
    for(int i=s1.size()-1;i>=0;i--)
    {
        if(a3[i]!=0)
        {
            index=i;
            break;
        }
    }
    for(int i=index;i>=0;i--)
    {
        cout<<a3[i];
    }
    return 0;
}

问题


  1. 数组越界问题
  • 问题点

    for(int i=0;i<=s1.size();i++) {
        a1[s1.size()-i-1]=s1[i]-'0';
    }
    

    这里的循环条件是 i <= s1.size(),但字符串的索引范围是 [0, s1.size()-1],因此当 i == s1.size() 时会导致数组越界。

  • 修复方法:将循环条件改为 i < s1.size()


  1. 借位逻辑错误
  • 问题点

    if(a1[i] < a2[i]) {
        a1[i] += 10;
        a1[i+1]--;
    }
    

    如果 a1[i+1] 已经为 0,则再次借位会导致负值,从而产生错误结果。

  • 修复方法:在借位时确保高位有足够值可以借。可以通过递归借位的方式解决:

    if(a1[i] < a2[i]) {
        int j = i;
        while(j < s1.size() && a1[j+1] == 0) {
            a1[j+1] = 9; // 借位后恢复为9
            j++;
        }
        if(j < s1.size()) {
            a1[j+1]--;
            a1[i] += 10;
        }
    }
    

  1. 前导零问题
  • 问题点

    for(int i=s1.size()-1;i>=0;i--) {
        if(a3[i] != 0) {
            index = i;
            break;
        }
    }
    

    如果结果为 0(例如 1 - 1),则 index 会保持初始值 0,导致输出多余字符。

  • 修复方法:在输出前检查是否所有位均为 0,并直接输出 0

    bool all_zero = true;
    for(int i=0;i<s1.size();i++) {
        if(a3[i] != 0) {
            all_zero = false;
            break;
        }
    }
    if(all_zero) {
        cout << "0";
        return 0;
    }
    

  1. 符号处理问题
  • 问题点:如果两个数相等(例如 1 - 1),当前代码会输出 -0,这是不正确的。
  • 修复方法:在输出符号前检查结果是否为 0:
    if(flag == '-') {
        bool all_zero = true;
        for(int i=0;i<s1.size();i++) {
            if(a3[i] != 0) {
                all_zero = false;
                break;
            }
        }
        if(!all_zero) {
            cout << flag;
        }
    }
    

solution 2

#include <bits/stdc++.h>
using namespace std;

int main() {
    string s1, s2;
    cin >> s1 >> s2;

    int a1[10100] = {0}, a2[10100] = {0}, a3[10100] = {0};
    char flag = '+';

    // 保证始终都是位数长的减去小的
    if(s1.size() < s2.size() || (s1.size() == s2.size() && s1 < s2)) {
        swap(s1, s2);
        flag = '-';
    }

    // 逆序存储
    for(int i = 0; i < s1.size(); i++) {
        a1[s1.size() - i - 1] = s1[i] - '0';
    }
    for(int i = 0; i < s2.size(); i++) {
        a2[s2.size() - i - 1] = s2[i] - '0';
    }

    // 高精度减法
    for(int i = 0; i < s1.size(); i++) {
        if(a1[i] < a2[i]) { // 需要借位的情况
            int j = i;
            while(j < s1.size() && a1[j+1] == 0) {
                a1[j+1] = 9; // 借位后恢复为9
                j++;
            }
            if(j < s1.size()) {
                a1[j+1]--;
                a1[i] += 10;
            }
        }
        a3[i] = a1[i] - a2[i];
    }

    // 检查是否所有位均为0
    bool all_zero = true;
    for(int i = 0; i < s1.size(); i++) {
        if(a3[i] != 0) {
            all_zero = false;
            break;
        }
    }
    if(all_zero) {
        cout << "0";
        return 0;
    }

    // 输出符号
    if(flag == '-') {
        bool has_non_zero = false;
        for(int i = 0; i < s1.size(); i++) {
            if(a3[i] != 0) {
                has_non_zero = true;
                break;
            }
        }
        if(has_non_zero) {
            cout << flag;
        }
    }

    // 找到倒序输出的起始位置
    int index = 0;
    for(int i = s1.size() - 1; i >= 0; i--) {
        if(a3[i] != 0) {
            index = i;
            break;
        }
    }

    // 输出结果
    for(int i = index; i >= 0; i--) {
        cout << a3[i];
    }

    return 0;
}

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

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

相关文章

【机器人】复现 GraspNet 端到端抓取点估计 | PyTorch2.3 | CUDA12.1

GraspNet是通用物体抓取的大规模基准的基线模型&#xff0c;值得学习和复现。 本文分享使用较新版本的PyTorch和CUDA&#xff0c;来搭建开发环境。 论文地址&#xff1a;GraspNet-1Billion: A Large-Scale Benchmark for General Object Grasping 开源地址&#xff1a;https:…

视频联网平台智慧运维系统:智能时代的城市视觉中枢

引言&#xff1a;破解视频运维的"帕累托困境" 在智慧城市与数字化转型浪潮中&#xff0c;全球视频监控设备保有量已突破10亿台&#xff0c;日均产生的视频数据量超过10万PB。然而&#xff0c;传统运维模式正面临三重困境&#xff1a; 海量设备管理失序&#xff1a;…

《网络管理》实践环节03:snmp服务器上对网络设备和服务器进行初步监控

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 应用拓扑图 3.0准备工作 所有Linux服务器上&#xff08;服务器和Agent端&#xff09;安装下列工具 yum -y install net-snmp net-snmp-utils 保证所有的HCL网络设备和服务器相互间能…

ubuntu中使用安卓模拟器

本文这里介绍 使用 android studio Emulator &#xff0c; 当然也有 Anbox (Lightweight)&#xff0c; Waydroid (Best for Full Android Experience), 首先确保自己安装了 android studio &#xff1b; sudo apt update sudo apt install openjdk-11-jdk sudo snap install…

py数据结构day3

思维导图&#xff1a; 代码1&#xff08;完成双向循环链表的判空、尾插、遍历、尾删&#xff09;&#xff1a; class Node:def __init__(self, data):self.data dataself.next Noneself.prev Noneclass DoubleCycleLink:def __init__(self):self.head Noneself.tail None…

STM32单片机入门学习——第8节: [3-4] 按键控制LED光敏传感器控制蜂鸣器

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.02 STM32开发板学习——第8节: [3-4] 按键控制LED&光敏传感器控制蜂鸣器 前言开…

【JavaScript】十三、事件监听与事件类型

文章目录 1、事件监听1.1 案例&#xff1a;击关闭顶部广告1.2 案例&#xff1a;随机点名1.3 事件监听的版本 2、事件类型2.1 鼠标事件2.1.1 语法2.1.2 案例&#xff1a;轮播图主动切换 2.2 焦点事件2.2.1 语法2.2.2 案例&#xff1a;模拟小米搜索框 2.3 键盘事件2.3.1 语法2.3.…

通过ansible+docker-compose快速安装一主两从redis+三sentinel

目录 示例主机列表 架构参考 文件内容 安装脚本 ansible变量&#xff0c;需修改 ansible配置文件和主机清单&#xff0c;需修改 运行方式 验证故障转移master 涉及redis镜像和完整的脚本文件 示例主机列表 架构参考 文件内容 安装脚本 #!/bin/bashset -e export pa…

mysql docker容器启动遇到的问题整理

好几个月没折腾mysql的部署&#xff0c;弄了下&#xff0c;又遇到不少问题 问题一&#xff1a;Access denied for user ‘root‘‘172.18.0.1‘ docker容器启动后&#xff0c;本地navicat 连接报这个错误 查到两个方案&#xff0c;一个貌似是要让root用户能在任意ip地址&…

长短期记忆神经网络(LSTM)基础学习与实例:预测序列的未来

目录 1. 前言 2. LSTM的基本原理 2.1 LSTM基本结构 2.2 LSTM的计算过程 3. LSTM实例&#xff1a;预测序列的未来 3.1 数据准备 3.2 模型构建 3.3 模型训练 3.4 模型预测 3.5 完整程序预测序列的未来 4. 总结 1. 前言 在深度学习领域&#xff0c;循环神经网络&…

C++多继承

可以用多个基类来派生一个类。 格式为&#xff1a; class 类名:类名1,…, 类名n { private: … &#xff1b; //私有成员说明; public: … &#xff1b; //公有成员说明; protected: … &#xff1b; //保护的成员说明; }; class D: public A, protected B, private C { …//派…

【深度学习新浪潮】DeepSeek近期的技术进展及未来动向

一、近期技术进展 模型迭代与性能提升 DeepSeek-V3-0324版本更新:2025年3月24日发布,作为V3的小版本升级,参数规模达6850亿,采用混合专家(MoE)架构,激活参数370亿。其代码能力接近Claude 3.7,数学推理能力显著提升,且在开源社区(如Hugging Face)上线。DeepSeek-R1模…

工业4.0时代下的人工智能新发展

摘要&#xff1a;随着德国工业4.0时代以及中国制造2025的提出&#xff0c;工业智能化的改革的时代正逐渐到来&#xff0c;然而我国整体工业水平仍然处于工业2.0水平。围绕工业4.0中智能工厂、智能生产、智能物流这三大主题&#xff0c;结合国内外研究现状&#xff0c;对人工智能…

监控易一体化运维:高性能与易扩展,赋能运维新高度

在当今数字化时代&#xff0c;云技术、大数据、智慧城市等前沿科技蓬勃发展&#xff0c;企业和城市对 IT 基础设施的依赖程度与日俱增。在这样的大环境下&#xff0c;运维系统的高性能与易扩展性对于保障业务稳定运行和推动发展的关键意义。今天&#xff0c;为大家深入剖析监控…

机器学习stats_linregress

import numpy as np from scipy import stats# r stats.linregress(xs, ys) 是一个用于执行简单线性回归的函数&#xff0c;通常来自 scipy.stats 库。# 具体含义如下&#xff1a;# stats.linregress&#xff1a;执行线性回归分析&#xff0c;拟合一条最佳直线来描述两个变量 …

Linux系统01---指令

目录 学习的方法 Linux 系统介绍 2.1 Unix 操作系统&#xff08;了解&#xff09; 2.2 Linux 操作系统&#xff08;了解&#xff09; 2.3 Linux 操作系统的主要特性&#xff08;重点&#xff09; 2.4 Linux 与 Unix 的区别与联系 2.5 GUN 与 GPL&#xff08;了解&#…

【蓝桥杯14天冲刺课题单】Day 8

1.题目链接&#xff1a;19714 数字诗意 这道题是一道数学题。 先考虑奇数&#xff0c;已知奇数都可以表示为两个相邻的数字之和&#xff0c;2k1k(k1) &#xff0c;那么所有的奇数都不会被计入。 那么就需要考虑偶数什么情况需要被统计。根据打表&#xff0c;其实可以发现除了…

DeepSeek 开源的 3FS 如何?

DeepSeek 3FS&#xff08;Fire-Flyer File System&#xff09;是一款由深度求索&#xff08;DeepSeek&#xff09;于2025年2月28日开源的高性能并行文件系统&#xff0c;专为人工智能训练和推理任务设计。以下从多个维度详细解析其核心特性、技术架构、应用场景及行业影响&…

通过 Docker Swarm 集群探究 Overlay 网络跨主机通信原理

什么是Overlay网络, 用于解决什么问题 ? Overlay网络通过在现有网络之上创建一个虚拟网络层, 解决不同主机的容器之间相互通信的问题 如果没有Overlay网络&#xff0c;实现跨主机的容器通信通常需要以下方法&#xff1a; 端口映射使用宿主机网络模式 这些方法牺牲了容器网络…

HarmonyOS NEXT开发进阶(十四):HarmonyOS应用开发者基础认证试题集汇总及答案解析

文章目录 一、前言二、判断题&#xff08;134道&#xff09;三、单选题&#xff08;210道&#xff09;四、多选题&#xff08;123道&#xff09;五、拓展阅读 一、前言 鸿蒙原生技能学习阶段&#xff0c;通过官方认证的资格十分有必要&#xff0c;在项目实战前掌握基础开发理论…