高精度算法相关基础入门例题及代码理解

前言

参考视频教程 洛谷 普及组试炼场 - 高精度算法

理解高精度算法,当题目数据规模过大时可能就需要考虑高精度解决了,高精度一般是通过数组输出~

以简单基础普及题型为例,可在洛谷上查找题目提交,代码仅供参考。

题目列表:

1.P1601 A+B Problem

2.P2142 高精度减法

3.P1303 A*B Problem

4.P1255 数楼梯

5.P1604 B进制星球

6.P1045 麦森数

7.算法提高 快速幂+取模

1.P1601 A+B Problem(高精)

题目描述

高精度加法,相当于a+b problem,不用考虑负数.

输入格式

分两行输入。a,b \leq 10^{500}a,b≤10500

输出格式

输出只有一行,代表a+ba+b的值

输入输出样例

输入 #1复制

1
1

输出 #1复制

2

输入 #2复制

1001
9099

输出 #2复制

10100

代码

#include <iostream>
#include <string>

using namespace std;

string aa,bb;    //可能超过long long 得string输入 
int a[10000010],b[10000010],c[10000010],la,lb,lc;

int main()
{
	cin>>aa>>bb;
	la = aa.length();
	lb = bb.length();
	for(int i=aa.length()-1;i>=0;i--)
	{
		a[aa.length()-i] = aa[i] - '0';
	}
	for(int i=bb.length()-1;i>=0;i--)
	{
		b[bb.length()-i] = bb[i] - '0';
	}
	lc = max(la,lb);
	for(int i = 1 ; i <= lc; i++)
	{
		c[i] += a[i] +b[i];  //必须是 += , 防止漏了进位的数  
		c[i+1] = c[i]/10;   //是否进位 
		c[i]%=10;  //取余 
	}
	if(c[lc+1]>0)     //这里是判断是否最高位进位 
	lc++;
	for(int i=lc;i>=1;i--)
	{
		cout<<c[i];
	}
}

2.P2142 高精度减法

题目描述

高精度减法。

输入格式

两个整数 a,ba,b(第二个可能比第一个大)。

输出格式

结果(是负数要输出负号)。

输入输出样例

输入 #1复制

2
1

输出 #1复制

1

代码

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

string aa, bb;    //可能超过long long 得string输入 
int a[10000010], b[10000010], c[10000010], la, lb, lc;


int main()
{
	cin >> aa >> bb;
	la = aa.length();
	lb = bb.length();

	if (la < lb || (la == lb && aa < bb))    //判断 aa,bb 的大小,当长度一致时string可以判断大小  
	{
		swap(aa, bb);
		swap(la, lb);
		cout << "-";
	}
	
	for (int i = aa.length() - 1; i >= 0; i--)
	{
		a[aa.length() - i] = aa[i] - '0';
	}
	for (int i = bb.length() - 1; i >= 0; i--)
	{
		b[bb.length() - i] = bb[i] - '0';
	}
	for (int i = 1; i <= la; i++)
	{
		if (a[i] < b[i])   //当当前位为小于时 
		{
			a[i] += 10;
			a[i + 1]--;
		}
		c[i] = a[i] - b[i];
	}
	while (c[la] == 0 && la > 1)   //判断前位是否为 0 
		la--;
	for (int i = la; i >= 1; i--)
	{
		cout << c[i];
	}

}

3.P1303 A*B Problem

题目描述

求两数的积。

输入格式

两行,两个整数。

输出格式

一行一个整数表示乘积。

输入输出样例

输入 #1复制

1 
2

输出 #1复制

2

说明/提示

每个数字不超过 10^{2000}102000 ,需用高精。

代码

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

string aa, bb;    //可能超过long long 得string输入 
int a[10000010], b[10000010], c[10000010], la, lb, lc;

int main()
{
	cin >> aa >> bb;
	la = aa.length();
	lb = bb.length();

	if (aa[0] == '-' && bb[0] != '-' || bb[0] == '-' && aa[0] != '-')  //貌似不需要 
	{
		cout << "-";
	}
	
	for (int i = aa.length() - 1; i >= 0; i--)
	{
		a[aa.length() - i] = aa[i] - '0';
	}
	for (int i = bb.length() - 1; i >= 0; i--)
	{
		b[bb.length() - i] = bb[i] - '0';
	}
	for (int i = 1; i <= la; i++)
	{
		for (int j = 1; j <= lb; j++)
		{
			c[i + j - 1] += a[i] * b[j];
			c[i + j] += c[i + j - 1] / 10;
			c[i + j - 1] %= 10;
		}
	}
	lc = la + lb;
	while (c[lc] == 0 && lc > 1)   //判断前位是否为 0 
		lc--;
	for (int i = lc; i >= 1; i--)
	{
		cout << c[i];
	}

}

4.P1255 数楼梯

题目描述

楼梯有 N 阶,上楼可以一步上一阶,也可以一步上二阶。

编一个程序,计算共有多少种不同的走法。

输入格式

一个数字,楼梯数。

输出格式

输出走的方式总数。

输入输出样例

输入 #1复制

4

输出 #1复制

5

说明/提示

  • 对于 60%60% 的数据,N*≤50;
  • 对于 100%100% 的数据,N≤5000。

代码

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

int a[500050], b[500050], c[500050], lc = 1;  //lc 为位数

int main()    //好好想想题目描述,会发现跟斐波那契数列差不多,看数据规模会发现可能需要用到高精度解决的方法
{
	int n;
	cin >> n;
	//	int a = 1,b=2,c;   //下面方法的前身,当不用数组时的斐波那契数列可以这样表示 
	//	for(int i=3;i<=n;i++)
	//	{
	//		c=a+b;
	//		a=b;
	//		b=c;
	//	}
	//  cout<<c; 
	a[1] = 1;
	b[1] = 2;
	for (int i = 3; i <= n; i++)
	{
		memset(c, 0, sizeof(c));  //每次都需要对 c 重新清零 
		for (int j = 1; j <= lc; j++)
		{
			c[j] += a[j] + b[j];
			c[j + 1] += c[j] / 10;
			c[j] = c[j] % 10;
		}
		if (c[lc + 1] > 0)
			lc++;
		for (int j = 1; j <= lc; j++)
		{
			a[j] = b[j];
		}
		for (int j = 1; j <= lc; j++)
		{
			b[j] = c[j];
		}
	}
	if (n >= 3)
	{
		for (int i = lc; i >= 1; i--)
		{
			cout << c[i];
		}
	}
	else if (n < 3)
	{
		switch (n)
		{
		case 0:cout << "0"; break;  //别忘了 break !! 
		case 1:cout << "1"; break;
		case 2:cout << "2"; break;
		}
	}
	return 0;
}

5.P1604 B进制星球

题目背景

进制题目,而且还是个计算器~~

题目描述

话说有一天,小Z乘坐宇宙飞船,飞到一个美丽的星球。因为历史的原因,科技在这个美丽的星球上并不很发达,星球上人们普遍采用B(2<=B<=36)进制计数。星球上的人们用美味的食物招待了小Z,作为回报,小Z希望送一个能够完成B进制加法的计算器给他们。 现在小Z希望你可以帮助他,编写实现B进制加法的程序。

输入格式

共3行第1行:一个十进制的整数,表示进制B。第2-3行:每行一个B进制数正整数。数字的每一位属于{0,1,2,3,4,5,6,7,8,9,A,B……},每个数字长度<=2000位。

输出格式

一个B进制数,表示输入的两个数的和。

输入输出样例

输入 #1复制

4
123
321

输出 #1复制

1110

代码

#include <iostream>
#include <string>
using namespace std;
string aa, bb;
int a[300020], b[300020], c[300020], la, lb, lc = 1;

int main()
{
	int n;
	cin >> n;
	cin >> aa >> bb;
	la = aa.length();
	lb = bb.length();
	for (int i = la - 1; i >= 0; i--)
	{
		if (aa[i] >= 'A')
		{
			a[la - i] = aa[i] - 'A' + 10;   //需要注意大于10进制的情况 
		}
		else
		{
			a[la - i] = aa[i] - '0';
		}
	}
	for (int i = lb - 1; i >= 0; i--)
	{
		if (bb[i] >= 'A')
		{
			b[lb - i] = bb[i] - 'A' + 10;
		}
		else
		{
			b[lb - i] = bb[i] - '0';
		}
	}
	lc = max(la, lb);
	for (int i = 1; i <= lc; i++)
	{
		c[i] += a[i] + b[i];
		c[i + 1] = c[i] / n;
		c[i] = c[i] % n;
	}
	if (c[lc + 1] > 0)
		lc++;
	for (int i = lc; i >= 1; i--)
	{
		if (c[i] >= 10)
		{
			cout << char(c[i] + 'A' - 10);
		}
		else
		{
			cout << c[i];
		}
	}
	return 0;
}

6.P1045 麦森数

题目描述

形如2P-1的素数称为麦森数,这时P*P*一定也是个素数。但反过来不一定,即如果P*P*是个素数,2P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。

任务:从文件中输入P(1000<P<3100000),计算2^P-1的位数和最后500位数字(用十进制高精度数表示)

输入格式

文件中只包含一个整数P(1000<P<3100000)

输出格式

第一行:十进制高精度数2^P-1的位数。

第2-11行:十进制高精度数2^P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0)

不必验证2^P-1与P是否为素数。

输入输出样例

输入 #1复制

1279

输出 #1

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087

代码

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int m[1010];
int a[1010];
int temp[1010];   //要有个临时保存的 

void xianchen()
{
	memset(temp, 0, sizeof(temp));
	for (int i = 1; i <= 500; i++)  //直接500给他 
	{
		for (int j = 1; j <= 500; j++)
		{
			temp[i + j - 1] += m[i] * a[j];
			temp[i + j] += temp[i + j - 1] / 10;
			temp[i + j - 1] %= 10;
		}
	}
	memcpy(m, temp, sizeof(m));  //把 temp 的值传给 m 
}

void zichen()
{
	memset(temp, 0, sizeof(temp));
	for (int i = 1; i <= 500; i++)
	{
		for (int j = 1; j <= 500; j++)
		{
			temp[i + j - 1] += a[i] * a[j];
			temp[i + j] += temp[i + j - 1] / 10;
			temp[i + j - 1] %= 10;
		}
	}
	memcpy(a, temp, sizeof(a));
}

int main()
{
	long long p;
	cin >> p;
	cout << int((p * log10(2)) + 1) << endl;   //求位数可以通过 log10()+1 解决 
	a[1] = 2;
	m[1] = 1;
	while (p != 0)
	{
		if (p % 2 == 1)
		{
			xianchen();
		}
		p /= 2;
		zichen();
	}
	m[1]--;
	for (int i = 500; i >= 1; i--)
	{
		if (i % 50 == 0 && i != 500)
		{
			cout << endl;
		}
		cout << m[i];
	}
}

7.算法提高 快速幂+取模

问题描述

给定A, B, P,求(A^B) mod P。

输入格式

输入共一行。
  第一行有三个数,N, M, P。

输出格式

输出共一行,表示所求。

样例输入

2 5 3

样例输出

2

数据规模和约定

共10组数据
  对100%的数据,A, B为long long范围内的非负整数,P为int内的非负整数。

代码

参考 https://www.bilibili.com/video/BV12r4y1w7tx?from=search&seid=7396560337832777912

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QU3068yC-1618067554342)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20210410154043709.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bMEDSQDQ-1618067554346)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20210410154051135.png)]

#include<iostream>
using namespace std;

int main()
{
	long long a, b;
	int p;
	cin >> a >> b >> p;
	long long ans = 1;
	a %= p;
	while (b != 0)
	{
		if (b & 1)  //即 b%2==1   ,可以加快速度 
		{
			ans = (ans * a) % p;
		}
		a = (a * a) % p;
		b >>= 1; //	即 b /= 2;
	}
	cout << ans << endl;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值