高精度加法讲解-And-2021年ACM竞赛班训练2021.5.13-问题 F: 最遥远的距离-题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高精度加法讲解-And-2021年ACM竞赛班训练2021.5.13-问题 F: 最遥远的距离-题解相关的知识,希望对你有一定的参考价值。

C++高精度减法

前面已经介绍了C++的高精度加法,以及如何重载
想要了解的小朋友可以点击这里

同样,我们定义一个结构体MyNum。

struct myNum{
    string num;  // 里面的数是倒着的
};

同样需要重载输入输出流

istream& operator >> (istream &in, myNum& a)  // 重载运算符“ >> ”, 记得a前面加上引用。
{
    in>>a.num;  // 如果要用cin,那么这就相当于cin>>a.num
    reverse(a.num.begin(),a.num.end());  // 把a.num倒置
    return in;
}


ostream& operator << (ostream &out, myNum a)
{
    reverse(a.num.begin(),a.num.end());
    out<<a.num;
    return out;
}

emmm,实在不行就记住吧,或者说先理解一下后面的加减法的重载,也许再理解这个会简单一些。

之后就需要重载减法了。这里先简单一点,采用正整数做加数。(但不保证结果不为负

回忆一下小学时学的减法运算法则:
两个正整数相减,先把长的数放在上面,把短的数放在下面:
小学减法

然后,对短的数的每一位,用长的数的相对应的那一位减去这一位再减去上一位的借位,如果不够减就向上借位。
长的数的超出短的数的部分就只需要考虑借位了。
同时,需要考虑结果是否为负,以及是否是“000”

如果要比较两个数的大小,可以:

bool operator < (const myNum&a, const myNum&b)
{
    int ka=a.num[a.num.size()-1]=='-'?-1:1; //其实对于此题可以不用考虑本来就是负数的情况
    int kb=b.num[b.num.size()-1]=='-'?-1:1;
    if(ka!=kb)//一正一负
        return ka==-1?true:false;
    int la=a.num.size(),lb=b.num.size();
    if(ka==-1)la--,lb--;
    if(la!=lb)return la<lb;
    for(int i=la-1;i>=0;i--)
        if(a.num[i]!=b.num[i])
            return ka==1?(a.num[i]<b.num[i]):(a.num[i]>b.num[i]);
    return false; //相等
}

然后,我们就先判断两个数哪个数更大,把大的放在上面,小的放在下面,进行减法运算。

代码如下:

myNum operator - (const myNum&a, const myNum&b)
{
    myNum ans;
    int la=a.num.size(),lb=b.num.size();
    string first,second;
    int k=1;
    if(a<b)first=b.num,second=a.num,swap(la,lb),k*=-1;//使得第一个大于第二个
    else first=a.num,second=b.num;
    int JieWei=0;
    for(int i=0;i<lb;i++)
    {
        int thisNum=first[i]-second[i]-JieWei;//不用-'0'了
        if(thisNum<0)
        {
            thisNum+=10;
            JieWei=1;
        }
        else JieWei=0;
        ans.num+=thisNum+'0';
    }
    for(int i=lb;i<la;i++)
    {
        int thisNum=first[i]-'0'-JieWei;
        if(thisNum<0)
        {
            thisNum+=10;
            JieWei=1;
        }
        else JieWei=0;
        ans.num+=thisNum+'0';
    }
    //大正数减小正数,最终借位是0
    for(int i=ans.num.size()-1;i>=0;i--)//去掉前导0
    {
        if(ans.num[i]!='0')break;
        ans.num.erase(--ans.num.end());
    }
    if(ans.num.size()==0)ans.num='0';
    else if(k==-1)ans.num+='-';
    return ans;
}

所以总体来看就是:

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
struct myNum{
    string num;//里面的数是倒着的
};

bool operator < (const myNum&a, const myNum&b)
{
    int ka=a.num[a.num.size()-1]=='-'?-1:1;
    int kb=b.num[b.num.size()-1]=='-'?-1:1;
    if(ka!=kb)//一正一负
        return ka==-1?true:false;
    int la=a.num.size(),lb=b.num.size();
    if(ka==-1)la--,lb--;
    if(la!=lb)return la<lb;
    for(int i=la-1;i>=0;i--)
        if(a.num[i]!=b.num[i])
            return ka==1?(a.num[i]<b.num[i]):(a.num[i]>b.num[i]);
    return false; //相等
}

myNum operator - (const myNum&a, const myNum&b)
{
    myNum ans;
    int la=a.num.size(),lb=b.num.size();
    string first,second;  // 第一个是大的数,第二个是小的数
    int k=1;
    if(a<b)first=b.num,second=a.num,swap(la,lb),k*=-1;//使得第一个大于第二个
    else first=a.num,second=b.num;
    int JieWei=0;
    for(int i=0;i<lb;i++)//对每小的数的每一位
    {
        int thisNum=first[i]-second[i]-JieWei;  // 与高精度加法相比,这里不用-'0'了; 这个数=第一个数的这一位-这个数的这一位-上一位的借位
        if(thisNum<0)  // 如果运算结果小于0
        {
            thisNum+=10;  // 变成正的
            JieWei=1;  // 借一位
        }
        else JieWei=0;  // 否则不借位
        ans.num+=thisNum+'0';  // 答案加上这一位
    }
    for(int i=lb;i<la;i++)  // 超出小的数的部分
    {
        int thisNum=first[i]-'0'-JieWei;  // 不用减去小的数了,但是要减'0'
        if(thisNum<0)  // 同上
        {
            thisNum+=10;
            JieWei=1;
        }
        else JieWei=0;
        ans.num+=thisNum+'0';
    }
    //大正数减小正数,最终借位是0
    for(int i=ans.num.size()-1;i>=0;i--)  // 去掉前导0
    {
        if(ans.num[i]!='0')break;
        ans.num.erase(--ans.num.end());
    }
    if(ans.num.size()==0)ans.num='0';  // 如果最终答案就是0,那么也得输出
    else if(k==-1)ans.num+='-';  // 是否为负
    return ans;
}

istream& operator >> (istream &in, myNum& a)
{
    in>>a.num;
    reverse(a.num.begin(),a.num.end());
    return in;
}

ostream& operator << (ostream &out, myNum a)
{
    reverse(a.num.begin(),a.num.end());
    out<<a.num;
    return out;
}

int main()
{
	myNum a, b;
	cin>>a>>b;
	cout<<a-b<<endl;
	return 0;
}

那么对于我校OJ的这道题:

  • 题目分析
  • 注意事项
  • AC代码

  • 最遥远的距离

    传送门

    时间限制:1秒
    空间限制:128M


    题目描述

    世界上最遥远的距离,是加与减的距离。仅少一竖,却需重新重载。

    2021 − 1921 = 2021-1921= 20211921= 建党 100 100 100周年!

    给你两行两个正整数 a a a b b b,范围是 1 1 1 ~ 1 0 1 0 5 10^{10^5} 10105,数据不包含前导零,请输出 a − b a-b ab的结果。

    输入描述

    输入描述就在题目中。


    输出描述

    当然也在题目中。


    样例一

    输入

    2021
    1921
    

    输出

    100
    

    题目分析

    其实,看到这道题不难想到上一道题:Python大法好
    所以上一道题这么长,应该能够比较容易地猜出来是高精度加法。


    注意事项

    本次为了降低一点难度系数,输入只有正整数。
    但是运算结果可能为负。
    记得去掉前导0。


    AC代码

    //注释看上面吧,前面代码有注释
    #include <bits/stdc++.h>
    using namespace std;
    #define mem(a) memset(a, 0, sizeof(a))
    #define dbg(x) cout << #x << " = " << x << endl
    #define fi(i, l, r) for (int i = l; i < r; i++)
    #define cd(a) scanf("%d", &a)
    typedef long long ll;
    struct myNum{
        string num;
    };
    
    bool operator < (const myNum&a, const myNum&b)
    {
        int ka=a.num[a.num.size()-1]=='-'?-1:1;
        int kb=b.num[b.num.size()-1]=='-'?-1:1;
        if(ka!=kb)
            return ka==-1?true:false;
        int la=a.num.size(),lb=b.num.size();
        if(ka==-1)la--,lb--;
        if(la!=lb)return la<lb;
        for(int i=la-1;i>=0;i--)
            if(a.num[i]!=b.num[i])
                return ka==1?(a.num[i]<b.num[i]):(a.num[i]>b.num[i]);
        return false; 
    }
    
    myNum operator - (const myNum&a, const myNum&b)
    {
        myNum ans;
        int la=a.num.size(),lb=b.num.size();
        string first,second;
        int k=1;
        if(a<b)first=b.num,second=a.num,swap(la,lb),k*=-1;
        else first=a.num,second=b.num;
        int JieWei=0;
        for(int i=0;i<lb;i++)
        {
            int thisNum=first[i]-second[i]-JieWei;
            if(thisNum<0)
            {
                thisNum+=10;
                JieWei=1;
            }
            else JieWei=0;
            ans.num+=thisNum+'0';
        }
        for(int i=lb;i<la;i++)
        {
            int thisNum=first[i]-'0'-JieWei;
            if(thisNum<0)
            {
                thisNum+=10;
                JieWei=1;
            }
            else JieWei=0;
            ans.num+=thisNum+'0';
        }
        for(int i=ans.num.size()-1;i>=0;i--)
        {
            if(ans.num[i]!='0')break;
            ans.num.erase(--ans.num.end());
        }
        if(ans.num.size()==0)ans.num='0';
        else if(k==-1以上是关于高精度加法讲解-And-2021年ACM竞赛班训练2021.5.13-问题 F: 最遥远的距离-题解的主要内容,如果未能解决你的问题,请参考以下文章

    集合划分讲解-And-2021年ACM竞赛班训练2021.5.20-问题 E: 登上火星-题解

    2021年ACM竞赛班训练(十一)

    2021年ACM竞赛班训练 E题 调皮的摩尔

    buctoj2021年ACM竞赛班训练题解

    2021年ACM竞赛班训练2021.5.20-问题 E: 调皮的摩尔-题解

    2021年ACM竞赛班训练2021.5.21-问题 A: 尝试看到这道题吧-题解