题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3755
题目大意:
意思不难理解,就是找到以某个字符串为前缀的最小的斐波拉契数列,并输出是第几个斐波拉契数。找不到就输出-1;
思路:大数加法,字典树。
ps:通过这道题接触到了大数加法。(虽然之前在刘汝佳的那本算法书里看到过阶乘的,但当时匆匆略过了)
该题是多组输入,我们就对斐波拉契数列预处理,将1——100000的斐波拉契数列找出来。
将它们存入字典树。长度超过40的就只压入长度为41的前缀。
然后在每个节点存入以当前前缀为最小的斐波拉契数的序号。
ps:斐波拉契数列不能多存了一个!只要你超过了100000个就wa,它卡了这个点;
之所以不全部存入是为了节省空间。不然会RE。
然后代码应该就能AC了。
ps:本人代码跑了8330ms,感觉都要tle了。看到他们都是几百ms就ac了,不造怎么写的。时间问题就没有去看。
代码如下
1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 string fib(string s1,string s2) 5 { 6 if(s1.length()<s2.length()) 7 { 8 string temp=s1; 9 s1=s2; 10 s2=temp; 11 } 12 int i,j; 13 for(i=s1.length()-1,j=s2.length()-1;i>=0;i--,j--) 14 { 15 s1[i]=char(s1[i]+(j>=0?s2[j]-‘0‘:0)); 16 if(s1[i]-‘0‘>=10) 17 { 18 s1[i]=char((s1[i]-‘0‘)%10+‘0‘); 19 if(i) s1[i-1]++; 20 else s1=‘1‘+s1; 21 } 22 } 23 return s1; 24 } 25 string a[100002]; 26 int cnt=1; 27 int sum[10000050][11]; 28 int num[10000050]; 29 void add(string s,int number) 30 { 31 int root=0; 32 for(int i=0;i<s.length()&&i<42;i++) 33 { 34 int xx=s[i]-‘0‘; 35 if(!sum[root][xx]) 36 { 37 sum[root][xx]=cnt++; 38 num[sum[root][xx]]=number;//存入最小的前缀,因为数列本身就是从小到大排,存入序号就ok 39 } 40 root=sum[root][xx]; 41 } 42 } 43 int Find(string s) 44 { 45 int root=0; 46 for(int i=0;i<s.length();i++) 47 { 48 int xx=s[i]-‘0‘; 49 root=sum[root][xx]; 50 if(root==0) 51 return 0; 52 } 53 return num[root]; 54 } 55 int main() 56 { 57 a[1]="1"; 58 a[2]="1"; 59 add(a[1],1); 60 add(a[2],2); 61 for(int i=3;i<=100000;i++)//预处理 62 { 63 a[i]=fib(a[i-1],a[i-2]); 64 add(a[i],i); 65 } 66 int T; 67 while(cin>>T) 68 { 69 int t=0; 70 string st; 71 while(T--) 72 { 73 t++; 74 cin>>st; 75 int tmp=Find(st); 76 if(tmp){ 77 cout<<"Case #"<<t<<": "<<tmp-1<<endl;//因为题目从0开始算,所以减一 78 }else{ 79 cout<<"Case #"<<t<<": "<<-1<<endl; 80 } 81 } 82 } 83 return 0; 84 }
时间: 2024-10-03 23:10:27