高精度运算
如果出题老师想要难为你,他可能会给你构造一些超出int,甚至long long 范围的数据
在你瞪着RE发呆的时候,考虑考虑数据范围——是不是该用高精度了?
数据太大,只能当字符串读(只针对数字,因为如果是字符串就直接读了)
读入优化
- 普通的读入优化:
//读整数
int Read(){
int i=0,f=1;//i读数字,f读符号
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());//一路避开不是数字或负号的字符,最后一次读到首位或负号
if(ch=='-'){
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar()){
i=(i<<3)+(i<<1)+ch-'0';
}
return i*f;
}
//如果只有正整数,情况就会简单得多
int Read(){
int i=0;
char ch;
for(ch=getchar();!isdigit(ch);ch=getchar());
for(;isdigit(ch);ch=getchar()){
i=(i<<3)+(i<<1)+ch-'0';
}
return i;
}
- 稍微修改一下——把数据都读到字符串/数组里,再大的位数都接受得了
//高精度读法 为了计算方便,倒着存数字
void Read(){
int i=0,num[1000];
char ch;//num存数据(从下标0或1开始都行)
for(ch=getchar();!isdigit(ch);ch=getchar());
//次for循环不要也行,用scanf("%d ",&x)消掉空格,scanf("%d\n",&x)消掉换行符
//小心getline,gets等语句会读空格,换行符
//不知道数位用这个:
int a[1000];
for(;isdigit(ch);ch=getchar()){
i++;
a[i]=ch-'0';
}
while(i--){
num[j]=a[i];
j++;
}
//知道数位:
for(int i=n-1;i>=0;i--){
num[i]=ch-'0';
ch=getchar();
}
}
//如果你喜欢用数组,try this
void Read(){
int i=0,num[1000];
char ch[1000];
/*选一个*/cin>>ch;scanf("%s",ch);gets(ch)/*小心它的换行符*/
for(int i=0;i<strlen(ch);i++)
num[strlen(ch)-i-1]=ch[i]-'0';
}
高精度四则运算
模拟普通的四则运算,数位是倒着写的
- 加法
#include<bits/stdc++.h>
using namespace std;
char ch[300];
int x,a[300],b[300],c[300],n,m;
int main()
{
cin>>ch;
n=strlen(ch);
for(int i=0;i<n;i++)
a[n-i]=ch[i]-'0';
cin>>ch;
m=strlen(ch);
for(int i=0;i<m;i++)
b[m-i]=ch[i]-'0';
if(n<m)n=m;
x=0;
for(int i=1;i<=n;i++)
{
c[i]=(a[i]+b[i]+x)%10;
x=(a[i]+b[i]+x)/10;
}
if(x>0)
{
n++;
c[n]=x;
}
for(int i=n;i>=1;i--)
cout<<c[i];
return 0;
}
Tips:
- /10去个位,%10取个位
- 初识进位
- 减法
#include<bits/stdc++.h>
using namespace std;
string st1,st2;
int n,m,a[300],b[300],s[300],x;
int main()
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(s,0,sizeof(s));
cin>>st1;
n=st1.size();
for(int i=0;i<n;i++)
a[n-i]=st1[i]-'0';
cin>>st2;
m=st2.size();
for(int i=0;i<m;i++)
b[m-i]=st2[i]-'0';
if(m>n||(m==n&&st1<st2))
{
cout<<"-";
for(int i=1;i<=m;i++)
swap(a[i],b[i]);
swap(m,n);
}
for(int i=1;i<=n;i++)
{
x=a[i]+10-b[i];
s[i]=x%10;
a[i+1]=a[i+1]+x/10-1;//下一位被减数,注意借位
}
while(n>1&&s[n]==0)n--;
for(int i=n;i>=1;i--)cout<<s[i];//i--!!!!!!!!
return 0;
}
Tips:
- 管他三七二十一,先借一位再说
- 出来借,总是要还的
- 小心负数
- 乘法
#include<bits/stdc++.h>
using namespace std;
char ch[300];
int a[300],b[300],s[300],n,m,x,w;
int main()
{
cin>>ch;
n=strlen(ch);
for(int i=0;i<n;i++)a[n-i]=ch[i]-'0';
cin>>ch;
m=strlen(ch);
for(int i=0;i<m;i++)b[m-i]=ch[i]-'0';
for(int i=1;i<=n;i++)
{
x=0;
for(int j=1;j<=m;j++)
{
x=a[i]*b[j]+x+s[i+j-1];
s[i+j-1]=x%10;
x=x/10;
}
s[i+m]=s[i+m]+x;//reminder:乘法最高位=以前重叠位数+进位
}
w=n+m;//reminder:n位数*m位数→n+m位数
while(s[w]==0&&w>1)w--;
for(int i=w;i>0;i--)cout<<s[i];
return 0;
}
Tips:
- 乘法的进位可能会超过10,不用担心,只要塞给下一位,下一位就会处理好
- n位数*m位数得到(n+m)位数
- 结果不一定就一定是(n+m)位数,再输出之前还要去首位之前无意义的零
- 除法(高精度除以单精度)
#include<bits/stdc++.h>
using namespace std;
int cs,bcs[300],shang[300],n,x,j;
char ch[300];
int main()
{
cin>>ch;
cin>>cs;
n=strlen(ch);
for(int i=0;i<n;i++)bcs[i]=ch[i]-'0';
for(int i=0;i<n;i++)
{
shang[i]=(bcs[i]+10*x)/cs;
x=(bcs[i]+x*10)%cs;
}
while(shang[j]==0&&n>j)j++;
for(int i=j;i<n;i++)cout<<shang[i];
cout<<endl;
cout<<x;
return 0;
}
Tips:
- 除法反而是最简单的(高精度除以单精度)
- 数组顺着存都没问题(而且更好)
- 也要记得去首位之前无意义的零