高精度__随笔

高精度

高精度既是在炸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),但思考难度太大(其实是本人不会),希望对你有所帮助。

posted @ 2025-05-24 19:42  海南方  阅读(25)  评论(0)    收藏  举报