题意:给你一串数,判断它是否是斐波那契数列前100000(不包括第100000项,WA了一次)项某一项的前缀。给你的数最多不超过40位。
思路:直接构造前100000项斐波那契数列的字典树是肯定超时的,并且我们只需要前40位。然而由于考虑到进位的问题,我们保存它的前50位,也就是说50位以后的进位我们就可以忽略不计了,但是只保存45位就会WA。总体来说还是不难的。具体见代码。
AC代码:
#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++)
{
int id=ss[i];
if(ch[u][id]==0)
{
ch[u][id]=sz;
memset(ch[sz],0,sizeof(ch[sz]));
sz++;
}
u=ch[u][id];
if(v[u]==-1) v[u]=ind;
}
}
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];
}
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++)//求斐波那契数列前100000项,只保留其前50位
{
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==50) k--;
add(fa+j,i,min(k-j+1,40));//判断的时候最多只判断前40位
}
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==50) k--;
add(fb+j,i,min(k-j+1,40));
}
}
}
}a;
int main()
{
int T;
char s[65];
a.init();
while(scanf("%d",&T)!=EOF)
{
cas=1;
while(T--)
{
scanf("%s",s);
a.find(s);
}
}
return 0;
}