UVA-12333 Revenge of Fibonacci

题目链接: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了,不造怎么写的。时间问题就没有去看。

 ps:知道在哪时间耗了那么久了,就是大数加法的那里最好判断一下是否数据超过了49位,是的话我们就舍去后面的位数。因为它前缀查询是不超过40位,那么我们就只需考虑前40位,但是会有误差,所以我们为了保险起见,我们选择49位。这样就避免误差了。现在附上第二份代码,耗时770ms,1s也能AC了

 

ps:不知道为什么我今天用自己的代码提交出现TLE,但是过段时间重复提交几次后又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 }

 

优化后的代码:

 

  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     if(s2.length()>49)
 14     {
 15         for(i=49,j=s2.length()+49-s1.length();i>=0;i--,j--)
 16         {
 17             s1[i]=char(s1[i]+(j>=0?s2[j]-'0':0));
 18             if(s1[i]-'0'>=10)
 19             {
 20                 s1[i]=char((s1[i]-'0')%10+'0');
 21                 if(i) s1[i-1]++;
 22                 else s1='1'+s1;
 23             }
 24         }
 25     }
 26     else
 27     {
 28         for(i=s1.length()-1,j=s2.length()-1;i>=0;i--,j--)
 29         {
 30             s1[i]=char(s1[i]+(j>=0?s2[j]-'0':0));
 31             if(s1[i]-'0'>=10)
 32             {
 33                 s1[i]=char((s1[i]-'0')%10+'0');
 34                 if(i) s1[i-1]++;
 35                 else s1='1'+s1;
 36             }
 37         }
 38     }
 39     return s1;
 40 }
 41 string a[100002];
 42 int cnt=1;
 43 int sum[10000050][11];
 44 int num[10000050];
 45 void add(string s,int number)
 46 {
 47     int root=0;
 48     for(int i=0;i<s.length()&&i<42;i++)
 49     {
 50         int xx=s[i]-'0';
 51         if(!sum[root][xx])
 52         {
 53             sum[root][xx]=cnt++;
 54             num[sum[root][xx]]=number;
 55         }
 56         root=sum[root][xx];
 57     }
 58 }
 59 int Find(string s)
 60 {
 61     int root=0;
 62     for(int i=0;i<s.length();i++)
 63     {
 64         int xx=s[i]-'0';
 65         root=sum[root][xx];
 66         if(root==0)
 67             return 0;
 68     }
 69     return num[root];
 70 }
 71 int main()
 72 {
 73     a[1]="1";
 74     a[2]="1";
 75     add(a[1],1);
 76     add(a[2],2);
 77     for(int i=3;i<=100000;i++)
 78     {
 79         a[i]=fib(a[i-1],a[i-2]);
 80         add(a[i],i);
 81     }
 82     int T;
 83     while(cin>>T)
 84     {
 85         int t=0;
 86         string st;
 87         while(T--)
 88         {
 89             t++;
 90             cin>>st;
 91             int tmp=Find(st);
 92             if(tmp){
 93                 cout<<"Case #"<<t<<": "<<tmp-1<<endl;
 94             }else{
 95                 cout<<"Case #"<<t<<": "<<-1<<endl;
 96             }
 97         }
 98     }
 99     return 0;
100 }

 

转载于:https://www.cnblogs.com/ISGuXing/p/7248071.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值