【模板】高精度算法

这其实就是一个高精度模板

题目描述

输入两个整数aba、b,求两个数的四则运算结果。

输入格式

输入第一行包含一个整数TT,第二行包含两个整数aba、b。

T=1T=1,表示计算a+ba+b

T=2T=2,表示计算aba−b

T=3T=3,表示计算aba∗b

T=4T=4,表示计算a/ba%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 0a101000000b101000000≤a≤10100000,0≤b≤10100000
6~10 T=2T=2 0a101000000b101000000≤a≤10100000,0≤b≤10100000
11~15 T=3T=3 0a10100000b10100000≤a≤1010000,0≤b≤1010000
16~20 T=4T=4 0a101000000b1040≤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 }

 

posted @ 2018-12-06 20:07  浅夜_MISAKI  阅读(469)  评论(0编辑  收藏  举报