高精度模板
加法
P1601 A+B Problem(高精)
#include<iostream>using namespace std;
const int N = 1e6 + 10;
int a[N],b[N],c[N];
int len1,len2,lenMax; //长度要提前定义在全局,在函数中要使用 void add(int c[],int a[],int b[])
{for(int i=0;i<lenMax;i++){c[i] += a[i] + b[i]; //这里一定是+= ,因为要加上 上一位 给的进位值 c[i + 1] = c[i] / 10; //先处理进位,给下一个位置c[i] %= 10; //再取模存入c[i] }//处理整体进位后结果长度要+1if(c[lenMax]) lenMax++;
}int main()
{string s1,s2;cin >> s1 >> s2;len1 = s1.length(), len2 = s2.length();lenMax = max(len1,len2);for(int i=0;i<len1;i++) a[i] = s1[len1-1-i] - '0';for(int i=0;i<len2;i++) b[i] = s2[len2-1-i] - '0';add(c,a,b); //a数组、b数组相加的结果放在c数组 for(int i=lenMax-1;i>=0;i--) cout << c[i]; return 0;
}
减法
P2142 高精度减法
#include<iostream>using namespace std;
const int N = 1e6 + 10;
int a[N],b[N],c[N];
int la,lb,lc;bool cmp(string& x,string& y) //如果第一个参数小就返回true
{if(x.size() != y.size()){return x.size() < y.size();}else{return x < y;}
}void sub(int c[],int a[],int b[])
{for(int i=0;i<lc;i++){c[i] += a[i] - b[i];if(c[i] < 0){c[i + 1] -= 1; //c[i+1] = -1;c[i] += 10;}}while(lc > 1 && c[lc-1] == 0 ) lc--; //lc最多减到1
}int main()
{string x,y;cin >> x >> y;if(cmp(x,y)) {swap(x,y); //确保x比y大,因为等会要用大数减小数cout << "-"; //交换了说明题目给的是大数减小数,结果为负数 }la = x.length(); lb = y.length(); lc = max(la,lb);//转化成数组形式 注意减去字符'0' for(int i=0;i<la;i++) a[i] = x[la-1-i] - '0';for(int i=0;i<lb;i++) b[i] = y[lb-1-i] - '0';//执行减法 sub(c,a,b); //输出c数组结果for(int i=lc-1;i>=0;i--) cout << c[i]; return 0;
}
注意:在消除前导0的时候 while(lc > 1 && c[lc-1] == 0 ) lc--;
该语句中的while
不能改为if
,虽然我们知道减法顶多会让较大的那个数字减少一位,所以可能就想这条语句顶多执行一次,但是如果这被减数和减数相等,那么减完的结果全部是0,这个时候必须要用while循环去除所有的0
。
乘法
P1303 A*B Problem
#include <iostream>
using namespace std;const int N = 1e6 + 10;
int a[N],b[N],c[N];
int la,lb,lc;void mul(int c[],int a[],int b[])
{//两层循环模拟列竖式相乘的过程 i和j位置的数相乘结果存在c数组的i+j位置for(int i=0;i<la;i++){for(int j=0;j<lb;j++){c[i+j] += a[i] * b[j]; //无进位乘法,最后处理进位 } }//处理进位 for(int i=0;i<lc;i++){c[i+1] += c[i] / 10; c[i] %= 10;}//处理前导零while(lc > 1 && c[lc-1] == 0) lc--;
}int main()
{string x,y;cin >> x >> y;la = x.size(); lb = y.size(); lc = la + lb; //相乘的结果的最大长度是两个因数的长度和 for(int i=0;i<la;i++) a[i] = x[la-1-i] - '0';for(int i=0;i<lb;i++) b[i] = y[lb-1-i] - '0';mul(c,a,b);for(int i=lc-1;i>=0;i--) cout << c[i]; return 0;
}
除法
P1480 A/B Problem
#include<iostream>
using namespace std;const int N = 1e6 + 10;int a[N],b,c[N];
int la,lc;typedef long long LL; //t有可能超intvoid div(int c[],int a[],int b)
{LL t = 0; //用来存每一位除完的余数for(int i = la - 1;i >= 0;i--) //从最高位开始处理,所以从la-1开始遍历{t = t * 10 + a[i];c[i] = t / b;t %= b; }while(lc > 1 && c[lc - 1] == 0) lc--;
}int main()
{string x;cin >> x >> b;la = x.size(); lc = la; //结果和被除数的长度是相同的,只不过结果可能出现前导0,最后处理for(int i = 0;i < la;i++) a[i] = x[la - i - 1] - '0';div(c,a,b);for(int i = lc - 1;i >= 0;i--) cout << c[i];return 0;
}
Q:为什么a要从高位开始处理还要倒着存?
A:方便记忆模板,四种高精度都是倒着存,而且方便处理前导0,处理的方式与其他的高精度都一样。但是正着存就要从数组的左边开始处理前导0,而且输出结果的时候还需要确定范围。
这是a正着存的模版:
#include<iostream>
using namespace std;const int N = 1e6 + 10;int a[N], b, c[N];
int la, lc;typedef long long LL; void div(int c[], int a[], int b)
{LL t = 0; // 用来存每一位除完的余数for(int i = 0; i < la; i++) // 这里应该是i++,不是i--{t = t * 10 + a[i];c[i] = t / b;t %= b; }// 处理前导零int k = 0;while(k < la && c[k] == 0) k++; // 找到第一个非零位lc = la - k;// 将结果前移for(int i = 0; i < lc; i++)c[i] = c[i + k];
}int main()
{string x;cin >> x >> b;la = x.size();for(int i = 0; i < la; i++) a[i] = x[i] - '0';div(c, a, b);// 输出结果for(int i = 0; i < lc; i++) cout << c[i];if(lc == 0) cout << "0"; // 处理结果为0的情况return 0;
}