目录
1、高精度算法是什么
2、高精度运算易错点
3、高精度加法
4、高精度减法
5、高精度乘法
1、两个高精度整数相乘
2、阶乘 —(n个低精度整数相乘,最终结果是高精度整数)
3、 Hanoi双塔问题——2*(pow(2,n)-1)——暴力的话会爆内存
6、高精度除法
1、高精度÷低精度
- 在c++中int、long long int等存储方式只能计算十几位的整数运算,而当我们想要计算更多位时,就需要用到高精度算法。
- 高精度算法:它是处理大数字的数学计算方法,在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除等运算。
思想:
- 将这种大数字拆开,拆成一位一位的,这样可已输入位数很长的数,接下来将每一位取出,存入数组中 ,然后用一个数组去存储每个数字,最后再将数组进行相应的运算(加、减、乘、除、等)。
高精度加法:
- 倒叙输入,倒序输出,但中间是正着运算;
- 相加之后的进位处理;
高精度减法:
- 考虑结果出现的正情况;
- 前导0的处理;
- 考虑减法的借位处理;
高精度乘法:
- 前导0的处理(0被相乘)!!!***容易被忽略***;
- 可以将乘法单个位数相乘再转化成加法的思想;
- 此时题目中没有涉及到负数的情况。如出现负数,只需考虑两个字符串第一位是否为负号,然后结尾特殊判断一下即可;
高精度除法:(高精度÷低精度)
- 输入、计算、输出、需要同时逆序或同时正序;
- 前导0的处理!!!***容易被忽略***;
- 不能考虑进位的情况!!
题目描述
给定两个正整数(不含前导 0),计算它们的和。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的和。
数据范围
1≤整数长度≤100000;
输入样例:
12 23
输出样例:
35
- 手动模拟——例如计算:567 + 28 = 595
- 先个位相加: 7 + 8 = 15,所以结果的个位是5,向十位进 1
- 再十位相加: 6 + 2 + 1(进位)= 9, 所以十位是 9,向百位进 0
- 在百位相加: 5 + 0 = 5, 所以结果的百位是 5
- 综上所述,计算结果为 595。
易错点:
- 一定要将数字进行倒叙输入,最后结果也是倒序输出,而中间的运算是正序运算。
- s1,s2两个字符串下标是从0开始的。
#include
#include
using namespace std;
const int N = 1e5 + 10;
string s1, s2;
int a[N], b[N], c[N];
int main()
{
cin >> s1 >> s2;
int j = 1, k = 1;//a、b数组的下标都是从1开始的
for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';
int ma = max(s1.size(), s2.size());//记录最大长度
int ans = 0;
for (int i = 1; i <= ma; i++)
{
ans = ans + (a[i] + b[i]);
c[i] = ans % 10;
ans = ans / 10;
}
if (ans) c[++ma] = ans;//**一定要注意最后是否会向前进一
for (int i = ma; i >= 1; i--)
{
cout << c[i];
}
return 0;
}
题目描述:
给定两个正整数(不含前导 0),计算它们的差,计算结果可能为负数。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的差。
数据范围
1≤整数长度≤100000
输入样例:
32 11
输出样例:
21
易错点:
减法的借位处理
相减为负数的处理
前导0的处理!!!!****容易被忽略ke'yi****
#include
#include
using namespace std;
const int N = 1e5 + 10;
string s1, s2;
int a[N], b[N], c[N], flag = 0;
int main()
{
cin >> s1 >> s2;
if (s1.size() < s2.size() || s1.size() == s2.size() && atoi(s1.c_str()) < atoi(s2.c_str()))
//这个判断是用来s1和s2那个字符串更大的。atoi(s1.c_str())—将s1字符串转化成数字进行比较
{
flag = 1;
swap(s1, s2);//保证s1始终是最大的字符串,同时做出正负的判断。
}
int j = 1, k = 1;//a,b下标从1开始
for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';
int ma = max(s1.size(), s2.size());//ma用来存最大长度的字符串个数
for (int i = 1; i <= ma; i++)
{
if (a[i] - b[i] < 0)//错位相减
{
a[i] = a[i] + 10;
a[i + 1] = a[i + 1] - 1;
}
c[i] = a[i] - b[i];
}
while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
if (flag == 1) printf("-");//负数的判断
for (int i = ma; i >= 1; i--)//
{
cout << c[i];
}
return 0;
}
题目描述
给定两个非负整数(不含前导 0) A 和 B,请你计算 A×B 的值。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共一行,包含 A×B 的值。
数据范围
1≤A的长度≤100000
0≤B≤10000;输入样例:
2 3
输出样例:
6
易错点:
- 前导0的处理(0被相乘)!!!***容易被忽略***;
- 可以将乘法单个位数相乘再转化成加法的思想;
- 此时题目中没有涉及到负数的情况,如出现负数,只需考虑两个字符串第一位是否为负号,然后结尾特殊判断一下即可。
#include
#include
using namespace std;
const int N = 1e6 + 10;
string s1, s2;
int a[N], b[N], s[N], c[N];
int main()
{
cin >> s1 >> s2;
int j = 1, k = 1;
for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';
for (int i = 1; i <= s1.size(); i++)
{
for (int j = 1; j <= s2.size(); j++)
{
s[i + j - 1] += a[i] * b[j];//单个数组逐一相乘
}
}
int ma = s1.size() + s2.size() - 1;//记录一下最高位数
int ans = 0;
for (int i = 1; i <= ma; i++)//高精度算法的核心
{
ans = ans + s[i];
c[i] = ans % 10;
ans = ans / 10;
}
if (ans) c[++ma] = ans;//考虑进位的情况
while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
for (int i = ma; i >= 1; i--)
{
cout << c[i];
}
return 0;
}
题目描述:
输入一个正整数 N,输出 N 的阶乘。
输入格式
输入包含多组测试数据。每组数据占一行,包含一个整数 N。
输出格式
每组数据输出占一行,输出 N 的阶乘。数据范围
1≤N≤1000,
每个输入最多包含 100 组数据输入样例:
4 5 15
输出样例:
24 120 1307674368000
#include
#include
#include
using namespace std;
const int N = 1e6 + 10;
int n, a[N], ans, x, m, d;
int main()
{
while (cin >> n)
{
a[0] = 1, d = 1;
for (int i = 1; i <= n; i++)//从1开始一直乘到本数;
{
x = 0;
for (int j = 0; j < d; j++)//几位就循环几次
{
ans = a[j] * i + x;//每一位乘上i,加上余数后所得的数
a[j] = ans % 10;//把最后一位给数组,其他的向前进
x = ans / 10;//把ans的最后一位数去掉
}
while (x != 0)//用while把c分配到各个高位
{
a[d++] = x % 10;//每进一位位数加一
x = x / 10;
}
}
for (int i = d - 1; i >= 0; i--)
{
cout << a[i];//存放从后向前存放,输出就要倒叙输出
}
cout << endl;
}
return 0;
}
题目描述
给定 A,B,C 三根足够长的细柱,在 A 柱上放有 2n 个中间有空的圆盘,共有 n 个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为 n=3 的情形)。
现要将这些圆盘移到 C 柱上,在移动过程中可放在 B 柱上暂存。要求:每次只能移动一个圆盘;
A、B、C 三根细柱上的圆盘都要保持上小下大的顺序;
任务:设 An 为 2n 个圆盘完成上述任务所需的最少移动次数,对于输入的 n,输出 An。输入格式
输入文件为一个正整数 n,表示在 A 柱上放有 2n 个圆盘。输出格式
输出文件仅一行,包含一个正整数,为完成上述任务所需的最少移动次数 An。数据范围
1≤n≤200
输入样例:2
输出样例:
6
思路:双塔问题所求的结果是单塔问题的2倍,即res=2*(pow(2,n)-1)=pow(2,n+1)-2;
#include
#include
#include
using namespace std;
const int N = 1e6 + 10;
int n, a[N], d, y = 2;
int main()
{
while (cin >> n)
{
d = 1, a[0] = 1;
for (int i = 1; i <= n + 1; i++)
{
int x = 0;
for (int j = 0; j < d; j++)
{
int ans = a[j] * y + x;
a[j] = ans % 10;
x = ans / 10;
}
while (x != 0)
{
a[d++] = x % 10;
x = x / 10;
}
}
a[0] -= 2;//进行减2的操作(2的n次方尾数一定大于等于2)
for (int i = d - 1; i >= 0; i--)
{
cout << a[i];
}
cout << endl;
}
return 0;
}
题目描述:
给定两个非负整数(不含前导 0) A,B,请你计算 A/B 的商和余数。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤100000,
1≤B≤10000,
B 一定不为 0!!输入样例:
7 2
输出样例:
3 1
#include
#include
using namespace std;
const int N = 1e6 + 10;
string s1;
int a[N], x, c[N];
int main()
{
cin >> s1 >> x;//x为低精度
int j = 1;
for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
int ma = s1.size(), ans = 0;
for (int i = ma; i >= 1; i--)//除法的核心运算
{
ans = ans * 10 + a[i];//上一位数*10加到下一位
c[i] = ans / x;
ans = ans % x;
}
while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
for (int i = ma; i >= 1; i--)
{
cout << c[i];
}
cout << endl << ans;//余数的输出
return 0;
}