字典树应用
题意:给你N个数,让你找出是不是前100000个斐波拉契数列的前40位,如果是则输出下标最小的那个斐波拉契数列数列的下标。
思路:求斐波拉契数列数列的前100000项的前40位。我们只需要计算前55位的和就行了,因为我们只要前40位,计算55位便可以消除误差
这个也是最近才知道的结论,要保留前n位,那么我们就要计算n+m为,m一定大时,产生的进位误差将消失
如:133+267=390,267+390=657,390+657=1047,657+1047=1704 ,假如我们只要前2位,则,13+26=39,26+39=65,39+65=104,10+65=75,已经开始出错了。
如果,我们计算前n位,所以我们要计算n+m位,m一定大时,进位产生的误差将消失。
把计算好的斐波拉契数列数列的前40项存入到字典树中,并且把斐波拉契数列数列的下标也存入字典数中。因为下标是从小到大存入的,所以给出的N个查询的数,找到的
也是斐波拉契数列的最小的下标
详情见代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define maxn 5100001
int cur=1;
struct node
{
int id;
int next[12];
void init()
{
id=-1;
memset(next,-1,sizeof(next));
}
}trie[maxn];
void Insert(char *s,int k)
{
//printf("%s\n",s);
int p=0;
int len=strlen(s);
for(int i=0; i<len; i++)
{
int x=s[i]-'0';
if(trie[p].next[x]==-1)
{
trie[cur].init();
trie[p].next[x]=cur++;
}
p=trie[p].next[x];
if(trie[p].id==-1)trie[p].id=k;//当前下标为-1 才改变下标,
//因为下标是从小到大依次存入到字典树中的
}
}
int Find(char *s,int len)
{
int p=0;
for(int i=0; i<len; i++)
{
int x=s[i]-'0';
if(trie[p].next[x]==-1)return -1;//没有找到
p=trie[p].next[x];
}
return trie[p].id;//找到返回下标
}
char a[70],b[70],c[70];
void add()//计算斐波拉契数列数列的前100000项的前40位
{
memset(a,'0',sizeof(a));
memset(b,'0',sizeof(b));
memset(c,'0',sizeof(c));
a[0]='1',a[1]='\0';
b[0]='1',b[1]='\0';
Insert(a,0);
Insert(b,1);
a[1]='0';b[1]='0';
int t=2,dc=0;
while(t<100000)
{
for(int i=0; i<64; i++)//大数相加,计算前64位
{
if(a[i]+b[i]+c[i]-'0'-'0'-'0'>9)//如果a+b,在加上当前位置的C要产生进位
c[i+1]+=1,c[i]+=a[i]+b[i]-'0'-'0'-10;
else c[i]+=a[i]+b[i]-'0'-'0';//加上不产生进位
}
dc=0;
for(int i=63; i>=0; i--)//找到最高位
{
if(c[i]>='1'&&c[i]<='9')
{
dc=i;
break;
}
}
if(dc>55)//保留55位
{
for(int i=0; i<=65; i++)
c[i]=c[i+1],b[i]=b[i+1];
dc--;
}
char dd[70];
int j=0;
for(j=0; j<64; j++)//得到斐波拉契数列的前43位
{
dd[j]=c[dc--];
if(dc==-1)break;
if(j==43)break;
}
dd[j+1]='\0';
Insert(dd,t);//插入字典树
//if(t==50)break;
strcpy(a,b);
strcpy(b,c);
memset(c,'0',sizeof(c));
t++;
}
}
int main()
{
trie[0].init();
add();
int t,ans=0;
char str[45];
scanf("%d",&t);
while(t--)
{
scanf("%s",str);
int len=strlen(str);
printf("Case #%d: %d\n",++ans,Find(str,len));
}
return 0;
}