高精度加法讲解-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= 2021−1921= 建党 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 a−b的结果。
输入描述
输入描述就在题目中。
输出描述
当然也在题目中。
样例一
输入
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: 登上火星-题解