【模板】高精度算法
这其实就是一个高精度模板
题目描述
输入两个整数a、ba、b,求两个数的四则运算结果。
输入格式
输入第一行包含一个整数TT,第二行包含两个整数a、ba、b。
当T=1T=1,表示计算a+ba+b
当T=2T=2,表示计算a−ba−b
当T=3T=3,表示计算a∗ba∗b
当T=4T=4,表示计算a/b,a%ba/b,a%b
输出格式
输出题目中描述运算的结果。
样例一
input
1
456 123
output
579
样例二
input
2
456 123
output
333
样例三
input
3
456 123
output
56088
样例四
input
4
456 123
output
3
87
限制与约定
所有测试数据的范围和特点如下表所示
测试点编号 | TT的范围 | n,mn,m的规模 |
---|---|---|
1~5 | T=1T=1 | 0≤a≤10100000,0≤b≤101000000≤a≤10100000,0≤b≤10100000 |
6~10 | T=2T=2 | 0≤a≤10100000,0≤b≤101000000≤a≤10100000,0≤b≤10100000 |
11~15 | T=3T=3 | 0≤a≤1010000,0≤b≤10100000≤a≤1010000,0≤b≤1010000 |
16~20 | T=4T=4 | 0≤a≤10100000,0≤b≤1040≤a≤10100000,0≤b≤104 |
时间限制:1s1s
空间限制:256MB
主要就是在重载运算符,十分毒瘤
结构体封装十分的爽快;
因为int类型能存很多位,只存一位太浪费,于是我们把每四位压到一起(当然你只要不爆int你也可以压更多位,只不过可能效率会变低);
然后结构体内封装一个mark,每次可以进行异或,各种运算和输出读入都会十分的方便
首先是读入,因为每四位压缩到了一起,所以读入需要维护下,而且要倒序,这样方便处理
1 bignum read() 2 { 3 scanf("%s",s); 4 bignum ans;memset(&ans,0,sizeof(ans)); 5 if(s[0]=='-')ans.mark^=1; 6 int len=strlen(s),cnt=0,ten=1; 7 ans.len=1; 8 for(int i=len-1;i>=ans.mark;i--) 9 { 10 ans.a[ans.len]+=(s[i]-'0')*ten; 11 ten*=10,cnt++; 12 if(cnt==5) 13 cnt=0,ten=1,ans.len++; 14 } 15 while(!ans.a[ans.len])ans.len--; 16 return ans; 17 }
然后是加法,其实就是一个模拟竖式,会发现它需要减法,这就是结构体封装的好处,可以互相调用;
而且符号的处理因为存了mark导致非常方便;
进位用一个mod(100000)来做
1 friend bignum operator+(bignum &x,bignum &y) 2 { 3 bignum ans;memset(&ans,0,sizeof(ans)); 4 if(x.mark &&y.mark) 5 ans.mark^=1; 6 else if(x.mark) 7 {x.mark^=1;return y-x;} 8 else if(y.mark) 9 {y.mark^=1;return x-y;} 10 ans.len=max(x.len,y.len); 11 for(int i=1;i<=ans.len;i++) 12 { 13 ans.a[i]+=x.a[i]+y.a[i]; 14 if(ans.a[i]>=mod) 15 ans.a[i]-=mod,ans.a[i+1]++; 16 } 17 if(ans.a[ans.len]>=mod) 18 ans.a[ans.len++]-=mod,ans.a[ans.len]++; 19 return ans; 20 }
然后是减法,依旧是模拟竖式,进退位也很好理解
1 friend bignum operator-(bignum &x,bignum &y) 2 { 3 bignum ans;memset(&ans,0,sizeof(ans)); 4 if(x.mark &&y.mark) 5 {x.mark^=1,y.mark^=1;return y-x;} 6 else if(x.mark) 7 {y.mark^=1;return x+y;} 8 else if(y.mark) 9 {y.mark^=1;return x+y;} 10 if(x!=y && x<=y) 11 swap(x,y),ans.mark^=1; 12 ans.len=max(x.len,y.len); 13 for(int i=1;i<=ans.len;i++) 14 { 15 if(x.a[i]<y.a[i]) 16 x.a[i]+=mod,x.a[i+1]--; 17 ans.a[i]=x.a[i]-y.a[i]; 18 } 19 while(!ans.a[ans.len]) 20 ans.len--; 21 return ans; 22 }
然后呢是乘法,这里涉及到一个小规律,就是那个i+j和i+j-1那个,用手模拟一下就懂了
1 friend bignum operator*(bignum &x,bignum &y) 2 { 3 bignum ans;memset(&ans,0,sizeof(ans)); 4 ans.mark=x.mark^y.mark; 5 ans.len=x.len+y.len; 6 for(int i=1;i<=x.len;i++) 7 for(int j=1;j<=y.len;j++) 8 { 9 ans.a[i+j]+=((ll)ans.a[i+j-1]+(ll)x.a[i]*(ll)y.a[j])/mod; 10 ans.a[i+j-1]=((ll)ans.a[i+j-1]+(ll)x.a[i]*(ll)y.a[j])%mod; 11 } 12 while((!ans.a[ans.len]) && ans.len>1) 13 ans.len--; 14 return ans; 15 }
然后是除法,这个处理会有一丢丢特殊,因为这个需要返回余数和商,所以用pair是最方便的,否则会很脑壳疼
1 friend pair<bignum,int> operator/(bignum &x,int y) 2 { 3 bignum ans;memset(&ans,0,sizeof(ans));int rec=0; 4 memcpy(&ans,&x,sizeof(x)); 5 for(int i=ans.len;i>=1;i--) 6 { 7 rec=ans.a[i]%y; 8 ans.a[i-1]+=rec*mod; 9 ans.a[i]/=y; 10 } 11 while((!ans.a[ans.len]) && ans.len>1) 12 ans.len--; 13 return make_pair(ans,rec); 14 }
然后是输出,注意那个%05d,因为每个int只使用了四位,全输出就不对了(这里同样体现了使用mark的好处)
1 void print(bignum &x) 2 { 3 if(x.len==1 && x.a[1]==0) 4 {printf("0");return;} 5 if(x.mark)printf("-"); 6 printf("%d",x.a[x.len]); 7 for(int i=x.len-1;i>=1;i--) 8 printf("%05d",x.a[i]); 9 return; 10 }
然后有两个>=和!=,这个是用来减法时候用,很好理解的
1 friend bool operator!=(bignum &x,bignum &y) 2 { 3 if(x.len!=y.len)return 1; 4 for(int i=1;i<=x.len;i++) 5 if(x.a[i]!=y.a[i]) 6 return 1; 7 return 0; 8 } 9 friend bool operator<=(bignum &x,bignum &y) 10 { 11 if(x.len<y.len) 12 { 13 for(int i=x.len;i>=1;i--) 14 if(x.a[i]!=y.a[i]) 15 return x.a[i]<y.a[i]; 16 return 1; 17 } 18 return x.len<y.len; 19 }
然后就A了这个恶心的高精度,可以当做模板来理解记忆
注意:memcpy后一个是source,用的时候要注意,还有带有&的memset不要宏定义
这里为什么要用那么多的“&"呢?因为&是一个地址,我们的结构体里有一个大数组,如果不加&就会RE爆炸,而且加了&之后就会直接修改外部变量的值,
如果一个函数需要多个返回值,那么就可以多传几个地址,就避免了pair;也就是说我的pair可以不写,pair要少用,可能会卡常;
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mod 100000 5 using namespace std; 6 typedef long long ll; 7 char s[111111];int T; 8 struct bignum{ 9 int a[111111],len,mark; 10 friend bool operator!=(bignum &x,bignum &y) 11 { 12 if(x.len!=y.len)return 1; 13 for(int i=1;i<=x.len;i++) 14 if(x.a[i]!=y.a[i]) 15 return 1; 16 return 0; 17 } 18 friend bool operator<=(bignum &x,bignum &y) 19 { 20 if(x.len<y.len) 21 { 22 for(int i=x.len;i>=1;i--) 23 if(x.a[i]!=y.a[i]) 24 return x.a[i]<y.a[i]; 25 return 1; 26 } 27 return x.len<y.len; 28 } 29 friend bignum operator+(bignum &x,bignum &y) 30 { 31 bignum ans;memset(&ans,0,sizeof(ans)); 32 if(x.mark &&y.mark) 33 ans.mark^=1; 34 else if(x.mark) 35 {x.mark^=1;return y-x;} 36 else if(y.mark) 37 {y.mark^=1;return x-y;} 38 ans.len=max(x.len,y.len); 39 for(int i=1;i<=ans.len;i++) 40 { 41 ans.a[i]+=x.a[i]+y.a[i]; 42 if(ans.a[i]>=mod) 43 ans.a[i]-=mod,ans.a[i+1]++; 44 } 45 if(ans.a[ans.len]>=mod) 46 ans.a[ans.len++]-=mod,ans.a[ans.len]++; 47 return ans; 48 } 49 friend bignum operator-(bignum &x,bignum &y) 50 { 51 bignum ans;memset(&ans,0,sizeof(ans)); 52 if(x.mark &&y.mark) 53 {x.mark^=1,y.mark^=1;return y-x;} 54 else if(x.mark) 55 {y.mark^=1;return x+y;} 56 else if(y.mark) 57 {y.mark^=1;return x+y;} 58 if(x!=y && x<=y) 59 swap(x,y),ans.mark^=1; 60 ans.len=max(x.len,y.len); 61 for(int i=1;i<=ans.len;i++) 62 { 63 if(x.a[i]<y.a[i]) 64 x.a[i]+=mod,x.a[i+1]--; 65 ans.a[i]=x.a[i]-y.a[i]; 66 } 67 while(!ans.a[ans.len]) 68 ans.len--; 69 return ans; 70 } 71 friend bignum operator*(bignum &x,bignum &y) 72 { 73 bignum ans;memset(&ans,0,sizeof(ans)); 74 ans.mark=x.mark^y.mark; 75 ans.len=x.len+y.len; 76 for(int i=1;i<=x.len;i++) 77 for(int j=1;j<=y.len;j++) 78 { 79 ans.a[i+j]+=((ll)ans.a[i+j-1]+(ll)x.a[i]*(ll)y.a[j])/mod; 80 ans.a[i+j-1]=((ll)ans.a[i+j-1]+(ll)x.a[i]*(ll)y.a[j])%mod; 81 } 82 while((!ans.a[ans.len]) && ans.len>1) 83 ans.len--; 84 return ans; 85 } 86 friend pair<bignum,int> operator/(bignum &x,int y) 87 { 88 bignum ans;memset(&ans,0,sizeof(ans));int rec=0; 89 memcpy(&ans,&x,sizeof(x)); 90 for(int i=ans.len;i>=1;i--) 91 { 92 rec=ans.a[i]%y; 93 ans.a[i-1]+=rec*mod; 94 ans.a[i]/=y; 95 } 96 while((!ans.a[ans.len]) && ans.len>1) 97 ans.len--; 98 return make_pair(ans,rec); 99 } 100 }a,b; 101 bignum read() 102 { 103 scanf("%s",s); 104 bignum ans;memset(&ans,0,sizeof(ans)); 105 if(s[0]=='-')ans.mark^=1; 106 int len=strlen(s),cnt=0,ten=1; 107 ans.len=1; 108 for(int i=len-1;i>=ans.mark;i--) 109 { 110 ans.a[ans.len]+=(s[i]-'0')*ten; 111 ten*=10,cnt++; 112 if(cnt==5) 113 cnt=0,ten=1,ans.len++; 114 } 115 while(!ans.a[ans.len])ans.len--; 116 return ans; 117 } 118 void print(bignum &x) 119 { 120 if(x.len==1 && x.a[1]==0) 121 {printf("0");return;} 122 if(x.mark)printf("-"); 123 printf("%d",x.a[x.len]); 124 for(int i=x.len-1;i>=1;i--) 125 printf("%05d",x.a[i]); 126 return; 127 } 128 int main() 129 { 130 scanf("%d",&T); 131 switch(T) 132 { 133 case 1: 134 a=read(),b=read(); 135 a=a+b; 136 print(a); 137 break; 138 case 2: 139 a=read(),b=read(); 140 a=a-b; 141 print(a); 142 break; 143 case 3: 144 a=read(),b=read(); 145 a=a*b; 146 print(a); 147 break; 148 case 4: 149 int mm; 150 a=read(),scanf("%d",&mm); 151 pair<bignum,int> c=a/mm; 152 print(c.first),printf("\n%d",c.second); 153 break; 154 } 155 }