某种序列
时间限制: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
- #include <stdio.h>
- #include <string.h>
- #define MAX 110
- #define MAXN 100
- #define CLR(arr) memset(arr,0,sizeof(arr))
- char a[4][MAX],c[3][MAX],temp1[MAX],temp2[MAX];
- char r[4][MAX];
- char b[3][MAX];
- void Strrev(int n,char *a){
- int j,len=n/2;
- char t;
- for(j=0;j<=len;j++){
- t=a[j];
- a[j]=a[n-j];
- a[n-j]=t;
- }
- }
- void add(const
char *a,const
char *b,char *r)//将a+b的结果保存在r中 - {
- int i=strlen(a)-1,j=strlen(b)-1,c=0,k=0;
- if(a[0]==‘0‘){
- memcpy(r,b,sizeof(temp1));
- return ;
- }
- if(b[0]==‘0‘){
- memcpy(r,a,sizeof(temp1));
- return ;
- }
- while(i>=0&&j>=0){
- r[k]=a[i--]+b[j--]+c-‘0‘;
- if(r[k]>‘9‘){
- r[k]-=10;
- c=1;
- }
- else c=0;
- k++;
- }
- while(i>=0){
- r[k]=a[i--]+c;
- if(r[k]>‘9‘){
- r[k]-=10;
- c=1;
- }
- else c=0;
- k++;
- }
- while(j>=0){
- r[k]=b[j--]+c;
- if(r[k]>‘9‘){
- r[k]-=10;
- c=1;
- }
- else c=0;
- k++;
- }
- if(c)r[k]=‘1‘;
- else k--;
- Strrev(k,r);
- }
- void mulp(const
char *a,const
char *b,char *r)//将a*c的结果保存在r中 - {
- int lena=strlen(a),lenb=strlen(b),i,j,k,c;
- for(i=lenb-1;i>=0;i--){
- j=lena-1;
- c=0;
- for(k=0;j>=0;k++){
- temp1[k]=(a[j--]-‘0‘)*(b[i]-‘0‘)+c;
- if(temp1[k]>9){
- c=(temp1[k])/10;
- temp1[k]%=10;
- }
- else c=0;
- temp1[k]+=‘0‘;
- }
- if(c)temp1[k]=c+‘0‘;
- else k--;
- Strrev(k,temp1);
- for(j=1;j<lenb-i;j++)temp1[k+j]=‘0‘;
- memcpy(temp2,r,sizeof(temp2));
- memset(r,0,sizeof(temp1));
- add(temp1,temp2,r);
- CLR(temp1);
- }
- if(r[0]==‘0‘||r[0]==0){
- CLR(r);
- r[0]=‘0‘;
- }
- }
- int main(){
- int i,j;
- b[0][0]=‘1‘;
- b[1][0]=‘0‘;
- b[2][0]=‘0‘;
- for(j=3;j<MAXN;j++){
- CLR(temp1);
- add(b[(j-1)%4],b[(j-2)%4],temp1);
- CLR(b[j%4]);
- add(temp1,b[(j-3)%4],b[j%4]);
- }//打出An中a0系数的表,这里使用取模循环来减小空间
- memcpy(c[0],b[(MAXN-1)%4],sizeof(c[0]));
- CLR(b);
- b[0][0]=‘0‘;
- b[1][0]=‘1‘;
- b[2][0]=‘0‘;
- for(j=3;j<MAXN;j++){
- CLR(temp1);
- add(b[(j-1)%4],b[(j-2)%4],temp1);
- CLR(b[j%4]);
- add(temp1,b[(j-3)%4],b[j%4]);
- }//a1系数的表
- memcpy(c[1],b[(MAXN-1)%4],sizeof(c[0]));
- CLR(b);
- b[0][0]=‘0‘;
- b[1][0]=‘0‘;
- b[2][0]=‘1‘;
- for(j=3;j<MAXN;j++){
- CLR(temp1);
- add(b[(j-1)%4],b[(j-2)%4],temp1);
- CLR(b[j%4]);
- add(temp1,b[(j-3)%4],b[j%4]);
- }//a2系数
- memcpy(c[2],b[(MAXN-1)%4],sizeof(c[0]));
- while(scanf("%s%s%s",a[0],a[1],a[2])!=EOF){//读取a0 a1 a2
- for(i=0;i<3;i++){
- CLR(temp1);
- mulp(c[i],a[i],r[i]);//计算a1,a2,a3各自和
- }
- CLR(temp1);
- add(r[0],r[1],temp1);
- add(temp1,r[2],r[3]);
- printf("%s\n",r[3]);//累加到r3中并输出
- CLR(a);
- CLR(r);//清0
- }
- return 0;
- }
这题的难点在于大数,加法我已经很熟了,但是乘法还没弄过,乘法是建立在加法的基础上,还是小学生算术做原理,逐位进行乘法并累加,主要有以下几点特别,进位不再只是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参数宏这招真方便(●‘?‘●)