Nyoj 114 某种序列(大数)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nyoj 114 某种序列(大数)相关的知识,希望对你有一定的参考价值。

某种序列

时间限制:3000 ms  |  内存限制:65535 KB

难度:4

描述

数列A满足An = An-1 + An-2 + An-3, n >= 3 
编写程序,给定A0, A1 A2, 计算A99

输入

输入包含多行数据 
每行数据包含3个整数A0, A1, A2 (0 <= A0, A1, A2 <= 100000000) 
数据以EOF结束

输出

对于输入的每一行输出A99的值

样例输入

1 1 1

样例输出

69087442470169316923566147

 

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define MAX 110
  4. #define MAXN 100
  5. #define CLR(arr) memset(arr,0,sizeof(arr))
  6. char a[4][MAX],c[3][MAX],temp1[MAX],temp2[MAX];
  7. char r[4][MAX];
  8. char b[3][MAX];
  9. void Strrev(int n,char *a){
  10.     int j,len=n/2;
  11.     char t;
  12.     for(j=0;j<=len;j++){
  13.         t=a[j];
  14.         a[j]=a[n-j];
  15.         a[n-j]=t;
  16.     }
  17. }
  18. void add(const char *a,const char *b,char *r)//将a+b的结果保存在r中
  19. {
  20.     int i=strlen(a)-1,j=strlen(b)-1,c=0,k=0;
  21.     if(a[0]==‘0‘){
  22.         memcpy(r,b,sizeof(temp1));
  23.         return ;
  24.     }
  25.     if(b[0]==‘0‘){
  26.         memcpy(r,a,sizeof(temp1));
  27.         return ;
  28.     }
  29.     while(i>=0&&j>=0){
  30.         r[k]=a[i--]+b[j--]+c-‘0‘;
  31.         if(r[k]>‘9‘){
  32.             r[k]-=10;
  33.             c=1;
  34.         }
  35.         else c=0;
  36.         k++;
  37.     }
  38.     while(i>=0){
  39.         r[k]=a[i--]+c;
  40.         if(r[k]>‘9‘){
  41.             r[k]-=10;
  42.             c=1;
  43.         }
  44.         else c=0;
  45.         k++;
  46.     }
  47.     while(j>=0){
  48.         r[k]=b[j--]+c;
  49.         if(r[k]>‘9‘){
  50.             r[k]-=10;
  51.             c=1;
  52.         }
  53.         else c=0;
  54.         k++;
  55.     }
  56.     if(c)r[k]=‘1‘;
  57.     else k--;
  58.     Strrev(k,r);
  59. }
  60. void mulp(const char *a,const char *b,char *r)//将a*c的结果保存在r中
  61. {
  62.     int lena=strlen(a),lenb=strlen(b),i,j,k,c;
  63.     for(i=lenb-1;i>=0;i--){
  64.         j=lena-1;
  65.         c=0;
  66.         for(k=0;j>=0;k++){
  67.             temp1[k]=(a[j--]-‘0‘)*(b[i]-‘0‘)+c;
  68.             if(temp1[k]>9){
  69.                 c=(temp1[k])/10;
  70.                 temp1[k]%=10;
  71.             }
  72.             else c=0;
  73.             temp1[k]+=‘0‘;
  74.         }
  75.         if(c)temp1[k]=c+‘0‘;
  76.         else k--;
  77.         Strrev(k,temp1);
  78.         for(j=1;j<lenb-i;j++)temp1[k+j]=‘0‘;
  79.         memcpy(temp2,r,sizeof(temp2));
  80.         memset(r,0,sizeof(temp1));
  81.         add(temp1,temp2,r);
  82.         CLR(temp1);
  83.     }
  84.     if(r[0]==‘0‘||r[0]==0){
  85.         CLR(r);
  86.         r[0]=‘0‘;
  87.     }
  88. }
  89. int main(){
  90.     int i,j;
  91.     b[0][0]=‘1‘;
  92.     b[1][0]=‘0‘;
  93.     b[2][0]=‘0‘;
  94.     for(j=3;j<MAXN;j++){
  95.         CLR(temp1);
  96.         add(b[(j-1)%4],b[(j-2)%4],temp1);
  97.         CLR(b[j%4]);
  98.         add(temp1,b[(j-3)%4],b[j%4]);
  99.     }//打出An中a0系数的表,这里使用取模循环来减小空间
  100.     memcpy(c[0],b[(MAXN-1)%4],sizeof(c[0]));
  101.     CLR(b);
  102.     b[0][0]=‘0‘;
  103.     b[1][0]=‘1‘;
  104.     b[2][0]=‘0‘;
  105.     for(j=3;j<MAXN;j++){
  106.         CLR(temp1);
  107.         add(b[(j-1)%4],b[(j-2)%4],temp1);
  108.         CLR(b[j%4]);
  109.         add(temp1,b[(j-3)%4],b[j%4]);
  110.     }//a1系数的表
  111.     memcpy(c[1],b[(MAXN-1)%4],sizeof(c[0]));
  112.     CLR(b);
  113.     b[0][0]=‘0‘;
  114.     b[1][0]=‘0‘;
  115.     b[2][0]=‘1‘;
  116.     for(j=3;j<MAXN;j++){
  117.         CLR(temp1);
  118.         add(b[(j-1)%4],b[(j-2)%4],temp1);
  119.         CLR(b[j%4]);
  120.         add(temp1,b[(j-3)%4],b[j%4]);
  121.     }//a2系数
  122.     memcpy(c[2],b[(MAXN-1)%4],sizeof(c[0]));
  123.     while(scanf("%s%s%s",a[0],a[1],a[2])!=EOF){//读取a0 a1 a2
  124.         for(i=0;i<3;i++){
  125.             CLR(temp1);
  126.             mulp(c[i],a[i],r[i]);//计算a1,a2,a3各自和
  127.         }
  128.         CLR(temp1);
  129.         add(r[0],r[1],temp1);
  130.         add(temp1,r[2],r[3]);
  131.         printf("%s\n",r[3]);//累加到r3中并输出
  132.         CLR(a);
  133.         CLR(r);//清0
  134.     }
  135.    return 0;
  136. }

这题的难点在于大数,加法我已经很熟了,但是乘法还没弄过,乘法是建立在加法的基础上,还是小学生算术做原理,逐位进行乘法并累加,主要有以下几点特别,进位不再只是1而是两个数向乘后取十位数,保留数不是减10而是取模10,而且+‘0‘转换成字符要放最后,否则为计算错误。我的方法就是把每一位都当个位,与另一个数相乘,得到的数再进行补位(也就是在结尾加0),虽说大数是主要难点,但是这题其实只要用加法,直接累加也能AC,就是对每个a0,a1,a2,我们直接加法递推出结果,还可以用循环队列的方法减小空间复杂度(其实也没必要,100*100左右还是不用担心MLE的),但是我们也可以发现,任意An可以表示成 a0,a1,a2的非负倍数和,而且对于An系数与 a0,a1,a2无关,于是我们可先递推出A99对应的各自系数,在用乘法与加法计算得出结果,我一开始就想到要这样,但是实现起来用了好久,早上1点起床,2点开始做,下午5点多才AC了,3个多小时,如果是比赛不知道死的多惨,注意时间耗在了加法乘法的实现与测试上,还有一开始以为系数不会很大,直接用int,发现溢出改用unsign int ,发现是正数(废话)愚蠢地以为安全了,就写了个数字转字符串函数,然后动手写高精度了,后来弄完高精度发现连测试样例都不对(这里要感谢一下样例,如果他犯贱用个0,0,0我就要搞更久),就猜想是不是爆了unsign int,换了下longlong,还是错,遍明白了自古斐波必大数的道理,只能改掉重来,然后交了,一次AC而且还是时间0 这题还是挺水了,居然还能难度4(你就会调软难度4 捏(╬▔皿▔)凸)几乎没什么坑,0,0,0算一个,但是这坑太容易想到了,于是能一次过,但耗时太长了,不过下次遇到大数类我应该能很快撸过,因为有了经验了,大数太常用了,需要更加地熟练,接下来想看一下图论的东西,又要啃那本白书了。。嗯,今天可以早点睡了o(* ̄▽ ̄*)ブ,对了,将memset弄成CLR参数宏这招真方便(●‘?‘●)

以上是关于Nyoj 114 某种序列(大数)的主要内容,如果未能解决你的问题,请参考以下文章

C++ 和序列化:有啥方法可以进行某种内省吗?

剑指offer-序列化二叉树

剑指offer:序列化二叉树

剑指offer:序列化二叉树

面试题37:序列化二叉树

[剑指offer]序列化二叉树