Revenge of Fibonacci HDU - 4099 (Trie樹運用)
阿新 • • 發佈:2018-11-06
題意:
給你一個數,這個數是斐波那契數列中的一個數的字首,找出這個字首的最小下標. 且這個下標如果超過了10W還沒有符合要求的話,就輸出-1.且輸入數不會超過40位,且沒有前導0.
分析:
直接思路那就是把前10W個斐波那契數列都搞出來構建字典樹,然後對每個輸入串判斷該字典即可. 這種想法不可行~,下標為10W的斐波那契數大概有幾萬位,不可能這樣加的.
我們只存前60位.50-60位可能會有進位,但是概率來說進位影響不到前40位.
如果新出來的數是61位了,我們只需對它對它進行擷取最後一位,同樣,和它即將相加的另外一個數末尾一位也截一位.
#include<bits/stdc++.h> using namespace std; const int maxn = 60*100000+1111; void add(char *a,char *b,char *c) { int len1 = strlen(a); int len2 = strlen(b); int i=len1-1,j=len2-1; int carry = 0; int k = 0; char tmp[111]; while(i>=0||j>=0) { int x,y,z; if(i<0)x=0; else x=a[i]-'0'; if(j<0)y=0; else y=b[j]-'0'; z=x+y+carry; tmp[k++]=z%10+'0'; carry=z/10; i--; j--; } if(carry)tmp[k++]=carry+'0'; for(int i=0;i<k;i++)c[i]=tmp[k-1-i]; c[k]=0; } struct node { int ch[maxn][10]; int v[maxn]; int sz; void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); memset(v,-1,sizeof v); } void insert(char *s,int vv) { int u=0,n=strlen(s); for(int i=0;i<n && i<40;i++) { int id=s[i]-'0'; if(ch[u][id]==0) { ch[u][id]=sz; memset(ch[sz],0,sizeof ch[sz]); v[sz]=-1; sz++; } u=ch[u][id]; if(v[u]<0) v[u]=vv; } } int find(char *s) { int n=strlen(s),u=0; for(int i=0;i<n;i++) { int id=s[i]-'0'; if(ch[u][id]==0) return -1; u=ch[u][id]; } return v[u]; } }trie; char str[3][111]; int main() { trie.init(); ///初始化前100000個F數 str[0][0]='1'; str[0][1]=0; trie.insert(str[0],0); str[1][0]='1'; str[1][1]=0; for(int i=2;i<100000;i++) { int len1=strlen(str[0]); int len2=strlen(str[1]); if(len2>60) { str[0][len1-1]=0; str[1][len2-1]=0; } add(str[0],str[1],str[2]); trie.insert(str[2],i); strcpy(str[0],str[1]); strcpy(str[1],str[2]); } int t; cin>>t; for(int kase=1;kase<=t;kase++) { scanf("%s",str[0]); int ans=trie.find(str[0]); printf("Case #%d: %d\n",kase,ans); } }