题意:给你一串数,判断它是否是斐波那契数列前100000(不包括第100000项,WA了一次)项某一项的前缀。给你的数最多不超过40位。
思路:直接构造前100000项斐波那契数列的字典树是肯定超时的,并且我们只需要前40位。然而由于考虑到进位的问题,我们保存它的前60位,也就是说60位以后的进位我们就可以忽略不计了,但是只保存45位就会WA。
#include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<cstdio> #include<string> #include<queue> #include<vector> #include<map> using namespace std; const int mx=4000005; const int inf=0x3f3f3f3f; int num,cas; int fa[50005],fb[50005]; struct node{ int ch[mx][10]; int v[mx]; int sz; void add(int *ss,int ind,int len) { int u=0,n=len; for(int i=0;i<n;i++) { //cout<<ss[i]; int id=ss[i]; if(ch[u][id]==0) { ch[u][id]=sz; //cout<<sz<<endl; memset(ch[sz],0,sizeof(ch[sz])); sz++; } u=ch[u][id]; if(v[u]==-1) v[u]=ind; } //cout<<endl; //cout<<sz<<endl; //cout<<ch[0][1]<<" "<<v[u]<<endl; } void find(char *s) { int u=0,n=strlen(s); for(int i=0;i<n;i++) { int id=s[i]-'0'; if(ch[u][id]==0) {printf("Case #%d: -1\n",cas++);return;} u=ch[u][id]; //cout<<id<<" "<<v[u]<<endl; } printf("Case #%d: %d\n",cas++,v[u]); } void init(){ memset(ch[0],0,sizeof(ch[0])); memset(v,-1,sizeof(v)); sz=1; int j,k,i; memset(fa,0,sizeof(fa)); memset(fb,0,sizeof(fb)); fa[50000]=1; fb[50000]=1; j=50000;k=50000; add(fa+50000,0,1); for(i=2;i<100000;i++) { if(i&1){ for(int ii=k;ii>=j;ii--) { fa[ii]+=fb[ii]; if(fa[ii]>9) {fa[ii-1]+=fa[ii]/10;fa[ii]=fa[ii]%10;} } if(fa[j-1]!=0) j--; if(k-j==60) k--; add(fa+j,i,min(k-j+1,40)); //for(int z=j;z<=k;z++) cout<<fa[z]; //cout<<endl; } else { for(int ii=k;ii>=j;ii--) { fb[ii]+=fa[ii]; if(fb[ii]>9) {fb[ii-1]+=fb[ii]/10;fb[ii]=fb[ii]%10;} } if(fb[j-1]!=0) j--; if(k-j==60) k--; add(fb+j,i,min(k-j+1,40)); //for(int z=j;z<=k;z++) cout<<fb[z]; //cout<<endl; } } } }a; int main() { //ios::sync int T; char s[65]; a.init(); while(scanf("%d",&T)!=EOF) { cas=1; while(T--) { scanf("%s",s); a.find(s); } } return 0; }