大数模板

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<conio.h>
  4 #include<stdlib.h>
  5 #include<time.h>
  6 #define N 10000
  7 // 大数模板。。。
  8 class BigNum
  9 {
 10   public:
 11     int s[N];  //存放各位数字,s[0]为符号位,1代表正数,-1代表负数
 12                //数组内高位存高位,123存在里面则为 1 3 2 1 ,第1个 1表示符号
 13     int len;   //长度
 14   public:
 15     BigNum()
 16     {
 17       memset(s,0,sizeof(s));  //初始化全0
 18       s[0]=1;                 //默认正数
 19       len=2;                  //变量初始化为0
 20     }
 21     void Display()            //输出
 22     {
 23       if(s[0]==-1) printf("-");
 24       for(int i=len-1;i>0;i--)
 25         printf("%d",s[i]);
 26     }
 27     void Sets(char *ts)        //赋值(bug 中途不能赋值)
 28     {
 29       int lts=strlen(ts);      //应对输入直接是 Sets("123");的情况,重新申请空间
 30       char *t;
 31       t=(char *)malloc(sizeof(char)*(lts+1));
 32       strcpy(t,ts);            //承接ts字符串
 33       Clear();
 34       int lt=strlen(t);       //获取字符串长度
 35       int flag=1;             //如果字符串带负号,flag为1,否则为0
 36       if(t[0]==‘-‘) s[0]=-1;  //设置符号位
 37       else
 38       {
 39         s[0]=1;
 40         flag=0;
 41       }
 42       int j=0;                //字符串高位消0
 43       for(int i=flag;i<lt-1;i++)
 44         if(t[i]==‘0‘) j++;
 45         else break;
 46       for(int i=j+flag;i<=lt;i++)
 47       {
 48         t[i-j]=t[i];
 49       }
 50       lt=lt-j;
 51       for(int i=lt;i>flag;i--)//如果字符串带负号,那么t[0]要被忽略
 52       {
 53         s[lt-i+1]=t[i-1]-‘0‘;
 54       }
 55       len=lt+!flag;           //如果字符串不带负号,那么len=lt+1
 56       free(t);
 57     }
 58     void Clear()
 59     {
 60       memset(s,0,sizeof(s));  //初始化全0
 61       s[0]=1;                 //默认正数
 62       len=2;                  //变量初始化为0
 63     }
 64     BigNum Nizhi()            //除法中用到,排除符号位颠倒数组
 65     {
 66       BigNum ans;
 67       ans.s[0]=s[0];
 68       for(int i=1;i<=len/2;i++)
 69       {
 70         ans.s[i]=s[len-i];
 71         ans.s[len-i]=s[i];
 72       }
 73       ans.len=len;
 74       return ans;
 75     }
 76     friend bool operator<(const BigNum &a,const BigNum &b);
 77     friend bool operator>(const BigNum &a,const BigNum &b);
 78     friend bool operator<=(const BigNum &a,const BigNum &b);
 79     friend bool operator>=(const BigNum &a,const BigNum &b);
 80     friend BigNum operator+(BigNum a,BigNum b);
 81     friend void operator+=(BigNum &a,BigNum b);
 82     friend BigNum operator-(BigNum a,BigNum b);
 83     friend void operator-=(BigNum &a,BigNum b);
 84     friend BigNum operator*(BigNum a,BigNum b);
 85     friend void operator*=(BigNum &a,BigNum b);
 86     friend BigNum operator/(BigNum a,BigNum b);
 87     friend void operator/=(BigNum &a,BigNum b);
 88     friend bool operator==(const BigNum &a,const BigNum &b);
 89 };
 90 bool operator<(const BigNum &a,const BigNum &b)
 91 {
 92   bool flag;
 93   if(a.s[0]==-1&&b.s[0]==1) return 1;      //如果a为负,b为正,那么a<b
 94   else if(a.s[0]==1&&b.s[0]==-1) return 0; //如果a为正,b为负,那么a>b
 95   else if(a.s[0]==1&&b.s[0]==1) flag=1;    //如果a、b都为正,flag=1,表示a、b大小和符号无关
 96   else flag=0;                             //如果a、b都为负,flag=0,表示a、b大小和符号有关
 97   // flag=1 时,a、b大小和除符号外的数字大小成正比,反之反比
 98   if(a.len>b.len) return !flag; //a的位数多,所以a大,返回0
 99   else if(a.len<b.len) return flag; //a的位数少,所以a小,返回1
100   else
101   {
102     int i=a.len;                    //从最高位开始比
103     while(i-->1)
104     {
105       if(a.s[i]>b.s[i]) return !flag;
106       else if(a.s[i]<b.s[i]) return flag;
107     }
108     return 0;                       //没有差异即相等返回0
109   }
110 }
111 bool operator<=(const BigNum &a,const BigNum &b) //同 <
112 {
113   bool flag; // flag=1 表示两者都是正的 =0表示两者都是负的
114   if(a.s[0]==-1&&b.s[0]==1) return 1;
115   else if(a.s[0]==1&&b.s[0]==-1) return 0;
116   else if(a.s[0]==1&&b.s[0]==1) flag=1;
117   else flag=0;
118   // flag 表示1 ,!flag 表示0
119   if(a.len>b.len) return !flag;
120   else if(a.len<b.len) return flag;
121   else
122   {
123     int i=a.len;
124     while(i-->1)
125     {
126       if(a.s[i]>b.s[i]) return !flag;
127       else if(a.s[i]<b.s[i]) return flag;
128     }
129     return 1;
130   }
131 }
132 bool operator>(const BigNum &a,const BigNum &b)
133 {
134   return !(a<=b);
135 }
136 bool operator>=(const BigNum &a,const BigNum &b)
137 {
138   return !(a<b);
139 }
140 bool operator==(const BigNum &a,const BigNum &b)
141 {
142   if(a.s[0]==-1&&b.s[0]==1) return 0;
143   else if(a.s[0]==1&&b.s[0]==-1) return 0;
144   if(a.len>b.len) return 0;
145   else if(a.len<b.len) return 0;
146   else
147   {
148     int i=a.len;
149     while(i-->1)
150     {
151       if(a.s[i]>b.s[i]) return 0;
152       else if(a.s[i]<b.s[i]) return 0;
153     }
154     return 1;
155   }
156 }
157 BigNum operator-(BigNum a,BigNum b)
158 {
159   BigNum ans;
160   if(a.s[0]==1&&b.s[0]==-1)      //如果a正,b负,那么等同于a+|b|
161   {
162     b.s[0]=1;
163     return a+b;
164   }
165   else if(a.s[0]==-1&&b.s[0]==1) //如果a负,b正,那么等同于-(|a|+b)
166   {
167     a.s[0]=1;
168     ans=a+b;
169     ans.s[0]=-1;
170     return ans;
171   }
172   else if(a.s[0]==-1&&b.s[0]==-1) //如果a负,b负,那么等同于|b|-|a|
173   {
174     a.s[0]=1;
175     b.s[0]=1;
176     return b-a;
177   }
178   else             //进到这一区域的,a为正,b为正
179   {
180     if(a<b)        //如果a<b,那么等同于-(b-a)
181     {
182       ans=b-a;
183       ans.s[0]=-1;
184     }
185     else           //进到这一区域a、b为正,且a>b,也就是说减出来的绝对是正数
186     {
187       int i=0;
188       int lm=a.len>b.len?a.len:b.len;  //由于减出来必定是正数,不需要考虑lm-1位<0的情况
189       for(int i=1;i<lm;i++)
190       {
191         int tmp=ans.s[i]+a.s[i]-b.s[i];
192         if(tmp<0)
193         {
194           ans.s[i+1]--;
195           tmp+=10;
196         }
197         ans.s[i]=tmp;
198       }
199       while(lm>2)    //清楚高位0,最多清楚到0为止
200       {
201         if(ans.s[lm-1]==0) lm--;
202         else break;
203       }
204       ans.len=lm;
205     }
206   }
207   return ans;
208 }
209 void operator-=(BigNum &a,BigNum b)
210 {
211   a=a-b;
212 }
213 BigNum operator+(BigNum a,BigNum b)
214 {
215   BigNum ans;
216   int lm=a.len>b.len?a.len:b.len;
217   if(a.s[0]*b.s[0]==1)   //如果两者符号位相同
218   {
219     ans.s[0]=a.s[0];     //结果符号位与任意一个相同
220     for(int i=1;i<lm;i++)
221     {
222       int tmp=ans.s[i]+a.s[i]+b.s[i];
223       if(tmp>=10)
224       {
225         ans.s[i+1]++;
226       }
227       ans.s[i]=tmp%10;
228     }
229     if(ans.s[lm]==0) ans.len=lm; //如果最高位没有进位,那么长度不变,否则加1
230     else ans.len=lm+1;
231   }
232   else                           //如果a、b符号不同,可以转化为减法
233   {
234     if(a.s[0]==1)
235     {
236       b.s[0]=1;
237       return a-b;
238     }
239     else
240     {
241       a.s[0]=1;
242       return b-a;
243     }
244   }
245   return ans;
246 }
247 void operator+=(BigNum &a,BigNum b)
248 {
249   a=a+b;
250 }
251
252 BigNum operator*(BigNum a,BigNum b)
253 {
254   BigNum ans;
255   ans.s[0]=a.s[0]*b.s[0];           //乘法和除法的符号位简单处理
256   for(int i=1;i<a.len;i++)
257   {
258     for(int j=1;j<b.len;j++)
259     {
260       ans.s[i+j-1]+=a.s[i]*b.s[j];  //先存
261     }
262   }
263   int maxt=a.len+b.len;             //最多位数
264   for(int i=1;i<maxt;i++)           //处理每个位上的数
265   {
266     if(ans.s[i]>=10)
267     {
268       ans.s[i+1]+=ans.s[i]/10;
269       ans.s[i]=ans.s[i]%10;
270     }
271   }
272   int i;
273   for(i=maxt;i>1;i--)               //处理高位0
274   {
275     if(ans.s[i]!=0) break;
276   }
277   ans.len=i+1;
278   return ans;
279 }
280 void operator*=(BigNum &a,BigNum b)
281 {
282   a=a*b;
283 }
284 BigNum operator/(BigNum a,BigNum b)
285 {
286   /*
287     思路: 首先从a的高位往低位数,如果还<b,那么就再加1位,知道>=b,然后遍历1-9,判断此时
288         合适取值,和平常手动计算思路一样
289   */
290   BigNum ans;
291   ans.s[0]=a.s[0]*b.s[0];
292   b.s[0]=1;       //中途比较需要
293   BigNum tmp;     //添位取值
294   tmp.len=1;      //刚开始为无值,就是说连a的最高位都还没纳入
295   BigNum zj;      //中间变量,比较时需要,由于数组是倒置的,所以加这一变量
296   ans.len=1;      //答案还是空的
297   int j=a.len;    //j固定指向a,不断取值
298   bool match=1;   //match为0退出循环
299   while(1)
300   {
301     while(1)   //如果还没取够值,就继续加位
302     {
303       if(j==1)    //如果a到了符号位,那么可以退出循环了
304       {
305         match=0;
306         break;
307       }
308       tmp.s[tmp.len++]=a.s[--j]; //加位,由于开始不好确定位数,所以直接正向不好办
309       zj=tmp.Nizhi();            //数组颠倒后再去比较
310       if(b<=zj) break;           //如果b<=zj了,就可以退出了,否则该位为0
311       ans.s[ans.len++]=0;
312     }
313     if(!match) break;            //match为0退出循环
314     int i;
315     BigNum r=b;                  //r为最大容许的乘后值
316     for(i=2;i<=10;i++)
317     {
318       BigNum p;
319       p.s[p.len-1]=i;    //获得 2 - 10 . 赋值过程不符常规,但由于下一步是乘,可以忽略该bug
320       BigNum u=b*p;      //如果u超过了中间变量,可以退出了,同i应该减1
321       if(zj<u) break;
322       r=u;               //乘得的最大数
323     }
324     i--;
325     ans.s[ans.len++]=i;          //逐位求值
326     zj=zj-r;                     //获得余数
327     BigNum q;
328     if(zj==q) zj.len--;          //如果余数为0,那么去掉,不能出现00,不然会出错
329     tmp=zj.Nizhi();              //重新逆置
330   }
331   ans=ans.Nizhi();               //逆置获得答案
332   while(ans.s[ans.len-1]==0&&ans.len>2) //高位消0
333   {
334     ans.len--;
335   }
336   return ans;
337 }
338 void operator/=(BigNum &a,BigNum b)
339 {
340   a=a/b;
341 }
342 int main()
343 {
344
345   return 0;
346 }
时间: 2025-01-11 00:25:39

大数模板的相关文章

timus 1547. Password Search【题意思路+大数模板】

题目地址传送门:URAL 1547 这道题需要用到大数的很多模板,推荐大家去刷刷! 题目大意:Vova忘记了在Timus OJ上面的密码了,密码是由小写字母(a~z)组成的,他只知道密码长度不大于n位,现在他需要用m台数据处理器对密码进行检索,其中检索顺序需要满足字典序.比如他的密码长度不大于2,那就需要依次检索a,b,..........,y,z,aa,ab,..........,zy,zz.输出每台数据检索器的检索区间,使得总的检索效率可以达到最高. 已知密码的总可能数不少于数据处理器个数.

ACM大数模板(支持正负整数)

之前就保留过简陋的几个用外部数组变量实现的简单大数模板,也没有怎么用过,今天就想着整合封装一下,封装成C++的类,以后需要调用的时候也方便得多. 实现了基本的加减乘除和取模运算的操作符重载,大数除以大数难度太大就没实现,另外还实现了比较运算符,方便实际使用贴近内置类型的体验. 话不多说,贴代码. 1 #include <stdio.h> 2 #include <string.h> 3 #include <ctype.h> 4 5 #define MAXBIT 1007

大数模板 poj3982

1. 这个模板不是自己写的,转载的别人转载的,还没学完c++的我,想写也没有那能力. 这个模板我用在了POJ的一道题上,传送门--POJ3982 一般大数的题,都可用这个模板解决,仅仅须要改动主函数就好了,可是假设不能独立写出来的话,不相当于白搭吗.所以我学完c++后会手写出模板的!. 注意,这个大数模板仅仅适用于不太大的模拟,几万位,肯定会爆内存的,兴许会补上功能更强大的模板和JAVA大数模板. #include<iostream> #include<cstdio> #inclu

简单大数模板(+ - )--待完善

水了ural的dp专题前三道1009,1012,1013,都是同一个问题,只是数据规模变大了. 题意大概是这样的:求一个k进制的n位数字,满足不含前导0和不含连续两个0的个数有多少个. dp[i][0]表示第i位为0有多少个满足条件,dp[i][1]表示i位不为0满足条件的个数,则结果就是dp[n][1]; 递推关系如下: dp[i][0]=dp[i-1][1]; dp[i][1]=(dp[i-1][0]+dp[i-1][1])*k; 顺便贴上简单的大数类 1 #include<iostream

Acdream 1210 Chinese Girls&#39; Amusement(大数模板运算 + 找规律)

传送门 Chinese Girls' Amusement Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description You must have heard that the Chinese culture is quite different from that of Europe or Rus

vijos - P1447开关灯泡 (大数模板 + 找规律 + 全然数 + python)

P1447开关灯泡 Accepted 标签:CSC WorkGroup III[显示标签] 描写叙述 一个房间里有n盏灯泡.一開始都是熄着的,有1到n个时刻.每一个时刻i,我们会将i的倍数的灯泡改变状态(即原本开着的现将它熄灭,原本熄灭的现将它点亮),问最后有多少盏灯泡是亮着的. 格式 输入格式 一个数n 输出格式 m,表示最后有m盏是亮着的 例子1 例子输入1[复制] 5 例子输出1[复制] 2 限制 1s 提示 范围:40%的数据保证,n<=maxlongint 100%的数据保证,n<=

bignum 大数模板

今天无意间看到一个很好的大数模板,能算加.减.乘.除等基本运算,但操作减法的时候只能大数减小数,也不支持负数,如果是两个负数的话去掉符号相加之后再取反就可以了,一正一负比较绝对值大小,然后相减.我借用了一下:(作过少许代码上的精简) 1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<algorithm> 5 #include<iostream> 6 using

Hdu 4762 网络赛 高精度大数模板+概率

注意题目中的这句话he put the strawberries on the cake randomly one by one,第一次选择草莓其实有N个可能,以某一个草莓为开头,然后顺序的随机摆放,所以最后的概率为n/m^(n-1),最后通过大数模板搞定该题的化简. C++代码 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<iomanip> 5 #include

大数模板 (C ++)

上次BC遇到一个大数题目,没有大数模板和不会使用JAVA的同学们GG了,赛后从队友哪里骗出大数模板.2333333,真的炒鸡nice(就是有点长),贴出来分享一下好辣. 1 //可以处理字符串前导零 2 #include <iostream> 3 #include <queue> 4 #include <cstdio> 5 #include <cstring> 6 #include <cstdlib> 7 #include <stack&g