厦门大学线下编程比赛第一题:求和
给定a和n,计算a+aa+aaa+aaaa+...+a...a(n个a) 的和。
输入描述:
测试数据有多组,以文件结尾。每行输入a,n(1<=a,n<=1000000)。
输出描述:
由于结果可能比较大,所以请输出答案mod 1000000007。
仔细审题,假设a=2,n=6;那么要求的和Σ = 2 + 22 + 222 + 2222 + 22222 + 222222
貌似也不难,只要知道n的长度,只需要把这些数值加起来不就行了吗?
再看题中提示:由于结果可能比较大,所以请输出答案mod 1000000007。
如果n很大时,超过定义数据类型的最大长度,这道题使用传统意义上的加法运算,貌似有点不可取。
看一下这个数据(a=3,n=8)
3
33
333
3333
33333
333333
3333333
33333333
个位数的和是 8 * 3 = 24,十位数的和是7 * 3 + 2= 21 + 2 = 23 (2来自个位和24的进位2),百位数的和是6 * 3 + 2 = 18+2=20 (2来自十位和23的进位2)......通过这个逻辑,我们可以推算出计算 给定a和n,计算a+aa+aaa+aaaa+...+a...a(n个a) 的和 的算法
1 #include<stdio.h> 2 #define MAX 1000000 3 int main() 4 { 5 int a = 3,n= 99; 6 int i,tmp=0; 7 char array[MAX+1]= {0}; 8 //倒序相加 9 for(i=0; i<n; i++) 10 { 11 tmp = a*(n-i)+tmp; 12 array[i] = tmp%10; 13 tmp = tmp/10; 14 } 15 while(tmp>0) 16 { 17 array[n++] = tmp%10; 18 tmp = tmp/10; 19 } 20 //倒序输出 21 for(i=n-1; i>=0; i--) printf("%d",array[i]); 22 printf("\n"); 23 24 return 0; 25 }
运行结果:
可见结果的确很长,题中输出描述:
由于结果可能比较大,所以请输出答案mod 1000000007
现在要做的事情就是如何将上面那么长的数据结果mod 1000000007。
我使用下面这种思路,比如有一个数 123456789,计算 123456789 mod 100007的值
第一步:123456789 - 100007000 = 23449789
第二步:23449789 - 10000700 = 13449089
第三步:13449089 - 10000700 = 3448389
第四步:3448389 - 1000070 = 2448319
第五步:2448319 - 1000070 = 1448249
第六步:1448249 - 1000070 = 448179
第七步:448179 - 100007 = 348172
第八步:348172 - 100007 = 248165
第九步:248165 - 100007 = 148158
第十步:148158 - 100007 = 48151
最终求得 123456789 mod 100007 = 48151
仔细想为什么呢?
既然思路已经有了,那么就上代码了。
1 #include<stdio.h> 2 #define MAX 1000000 3 int main() 4 { 5 int a = 3,n=99; 6 int i,tmp=0; 7 char array[MAX+2]= {'\0'}; 8 9 /* 10 在这里我们要论证一点 11 a的取值范围[1,9] 12 n的取值范围[1,1000000] 13 n*a的最大值为9*1000000 << Int32.MaxValue 14 所以我们可以使用以下逻辑对商数做处理 15 */ 16 for(i=0; i<n; i++) 17 { 18 //倒序相加 19 tmp = a*(n-i)+tmp; 20 array[i] = tmp%10; 21 tmp = tmp/10; 22 } 23 24 //处理多余商数(这个商数可能比较大,所以要用while循环做进位处理) 25 while(tmp>0) 26 { 27 array[n++] = tmp%10; 28 tmp = tmp/10; 29 } 30 31 //倒序输出(打印出结果值) 32 for(i=n-1; i>=0; i--) printf("%d",array[i]); 33 printf("\n"); 34 35 int n1=n; 36 while(n1-10>=0) 37 { 38 int b=0;//是不是大于1000000007 39 if (n-n1==0) 40 { 41 //判断前十位是不是大于1000000007,如果不大于,判断前11位 42 if(!b&&array[n1-1]>1)b=1; 43 if(!b&&array[n1-2]>0)b=1; 44 if(!b&&array[n1-3]>0)b=1; 45 if(!b&&array[n1-4]>0)b=1; 46 if(!b&&array[n1-5]>0)b=1; 47 if(!b&&array[n1-6]>0)b=1; 48 if(!b&&array[n1-7]>0)b=1; 49 if(!b&&array[n1-8]>0)b=1; 50 if(!b&&array[n1-9]>0)b=1; 51 if(!b&&array[n1-10]>7)b=1; 52 if (!b) 53 { 54 n1--; 55 continue; 56 } 57 } 58 59 60 b=0;//是否需要借位 61 if (array[n1-10]>=7) 62 { 63 array[n1-10]-=7; 64 b=0; 65 } 66 else 67 { 68 array[n1-10]+=3; 69 b=1; 70 } 71 72 for(i=9; i>=2; i--) 73 { 74 if(b) 75 { 76 if(array[n1-i]>=1) 77 { 78 array[n1-i]-=1; 79 b=0; 80 } 81 else 82 { 83 array[n1-i]=9; 84 b=1; 85 } 86 } 87 } 88 89 if (n-n1>0) 90 { 91 if(b) 92 { 93 array[n1-1]=array[n1]*10+array[n1-1]-2; 94 } 95 else 96 { 97 array[n1-1]=array[n1]*10+array[n1-1]-1; 98 } 99 array[n1]='\0'; 100 } 101 else 102 { 103 if(b) 104 { 105 array[n1-1]=array[n1-1]-2; 106 } 107 else 108 { 109 array[n1-1]=array[n1-1]-1; 110 } 111 } 112 n1=--n; 113 } 114 115 //倒序输出 116 for(i=n-1; i>=0; i--) printf("%d",array[i]); 117 printf("\n"); 118 119 return 0; 120 }
运算结果: