高精度__随笔
高精度
高精度既是在炸long long时,进行运算。看题。
高精度加法
P1601 A+B Problem(高精)
题目描述
高精度加法,相当于 a+b problem,不用考虑负数。
输入格式
分两行输入。\(a,b \leq 10^{500}\)。
输出格式
输出只有一行,代表 \(a+b\) 的值。
输入输出样例 #1
输入 #1
1
1
输出 #1
2
输入输出样例 #2
输入 #2
1001
9099
输出 #2
10100
说明/提示
\(20\%\) 的测试数据,\(0\le a,b \le10^9\);
\(40\%\) 的测试数据,\(0\le a,b \le10^{18}\)。
分析
可以用数组来模拟很长的数,用数组的每一位来代表每一位上的数字,即用n位数组来代表n位数字。
例如 523 + 495
| 第四位 | 第三位 | 第二位 | 第一位 | |
|---|---|---|---|---|
| 523 | 5 | 2 | 3 | |
| 495 | 4 | 9 | 5 | |
| 中间产物 | 9 | 11 | 8 | |
| 进位1 | 10 | 1 | 8 | |
| 进位2 | 1 | 0 | 1 | 8 |
tips:由于进位要从低位到高位,所以数在数组中的呈现是倒过来的,即用数组的第一位存数的第一个数。比如:1234,a[1] = 4, a[2] = 3,a[3] = 2, a[4] = 1。(事实上可以从第0位开始,但从第一开始方便思考)
P1601 A+B Problem(高精)参考代码:
#include<bits/stdc++.h>
using namespace std;
string s1,s2;//用string来获得数
int a[210],b[210],ans[210];//a[]表示数a,b[]表示数b,ans[]表示答案
int main(){
ios::sync_with_stdio(false);
cin.tie(0);//快读
cin>>s1>>s2;
int l1 = s1.length(), l2 = s2.length();
for(int i=1;i<=l1;i++) a[i] = s1[l1-i] -'0';//数转化为数组
for(int i=1;i<=l2;i++) b[i] = s2[l2-i] -'0';
int l = max(l1,l2)+1;
for(int i=1;i<=l;i++){
ans[i] = a[i] + b[i];
}
for(int i=1;i<=l;i++){//处理进位
ans[i+1] += ans[i]/10;//注意是+=
ans[i] %= 10;
}
while(!ans[l]) l--;
for(int i=max(l,1);i>=1;i--) cout<<ans[i];//需要注意,由于ans可能为0,所以l会减到小于1,所以i取max(l,1)
return 0;
}
高精度乘法
P1303 A*B Problem
题目背景
高精度乘法模板题。
题目描述
给出两个非负整数,求它们的乘积。
输入格式
输入共两行,每行一个非负整数。
输出格式
输出一个非负整数表示乘积。
输入输出样例 #1
输入 #1
1
2
输出 #1
2
说明/提示
每个非负整数不超过 \(10^{2000}\)。
分析
与加法类似,不多赘述。
| 数 | 第八位 | 第七位 | 第六位 | 第五位 | 第四位 | 第三位 | 第二位 | 第一位 |
|---|---|---|---|---|---|---|---|---|
| a | 5 | 2 | 3 | |||||
| b | 4 | 9 | 5 | |||||
| a*b[1] | 25 | 10 | 15 | |||||
| a*b[2] | 45 | 18 | 27 | |||||
| a*b[3] | 20 | 8 | 12 | |||||
| 中间产物 | 20 | 53 | 55 | 37 | 15 | |||
| 进位 | 2 | 5 | 8 | 8 | 8 | 5 |
tips:不难发现a[i]b[j]的贡献在i+j-1上(可由表得出),对于b[j],a[i]b[j]会在i的增加上往左移。
P1303 A*B Problem 参考代码:
//注意事项和注释同加法差不多
#include<bits/stdc++.h>
using namespace std;
int ans[40100];
int a[2000],b[2000];
string sa,sb;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>sa>>sb;
int la = sa.length();
int lb = sb.length();
for(int i=1;i<=la;i++) a[la-i+1] = sa[i-1]-'0';
for(int i=1;i<=lb;i++) b[lb-i+1] = sb[i-1]-'0';
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++){
ans[i+j-1] += a[i]*b[j];
}
}
for(int i=1;i<=la+lb;i++){
ans[i+1] += ans[i]/10;
ans[i]%=10;
}
int k = la+lb;
while(k>1&&ans[k]==0) k--;
for(int i=k;i>=1;i--) cout<<ans[i];
return 0;
}
继续。
P1009 [NOIP 1998 普及组] 阶乘之和
题目描述
用高精度计算出 \(S = 1! + 2! + 3! + \cdots + n!\)(\(n \le 50\))。
其中 ! 表示阶乘,定义为 \(n!=n\times (n-1)\times (n-2)\times \cdots \times 1\)。例如,\(5! = 5 \times 4 \times 3 \times 2 \times 1=120\)。
输入格式
一个正整数 \(n\)。
输出格式
一个正整数 \(S\),表示计算结果。
输入输出样例 #1
输入 #1
3
输出 #1
9
说明/提示
【数据范围】
对于 \(100 \%\) 的数据,\(1 \le n \le 50\)。
NOIP1998 普及组 第二题
分析
将高精度加法同高精度减法一起运用
P1009 [NOIP 1998 普及组] 阶乘之和 参考代码:
#include<bits/stdc++.h>
using namespace std;
int a[210] = {1},ans[210] = {1},n;
void flatten(int a[]){//展平
for(int i=0;i<=210;i++){
a[i+1] += a[i]/10;
a[i] %=10;
}
}
void add(){//高精度加法
for(int i=0;i<=210;i++) ans[i] += a[i];
flatten(ans);
}
void mul(int x){//高精度减法
for(int i=0;i<=210;i++) a[i]*=x;
flatten(a);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=2;i<=n;i++){
mul(i);
add();
}
int k=210;
while(!ans[k]) k--;
for(int i=max(k,0);i>=0;i--) cout<<ans[i];
return 0;
}
总结
高精度可以用来求大范围的数的运算,但上述展示的高精度仍有缺陷,如高精度加法只能是两个正数相加,高精度乘法同样也是。除此之外,时间复杂度达到了O(n2),虽然可以用快速傅里叶变换达到O(nlog2n),但思考难度太大(其实是本人不会),希望对你有所帮助。

浙公网安备 33010602011771号