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
-
#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参数宏这招真方便(●‘?‘●)
以上是关于Nyoj 114 某种序列(大数)的主要内容,如果未能解决你的问题,请参考以下文章