hdu 4099 Revenge of Fibonacci 字典树+斐波拉契数列数列

来源:互联网 发布:拍淘宝静物用什么相机 编辑:程序博客网 时间:2024/06/10 20:24

字典树应用

题意:给你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 5100001int 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;}


0 0
原创粉丝点击