题意:Fibonacci数的定义为: F(0)=F(1)=1,然后从F(2)开始,F(i)=F(i-1)+F(i-2)。例如,前10项Fibonacci 数分别为1,1,2,3,5,8,13,21,34,55...
有一天晚上,你梦到了Fibonacci,它告诉你一个有趣的Fibonacci 数。醒来以后,你只记得了它的开头几个数字。你的任务是找出以它开头的最小Fibonacci 数的序号。例如以12开头的最小Fibonacci 数是F(25)。
输入不超过40个数字,输出满足条件的序号。如果序号小于100000的Fibonacci 数均不满足条件,输出-1。
提示:本题有一定效率要求。如果高精度代码比较慢,可能会超时。
思路:高精度计算前100000个Fibonacci数,并将每个数字的前50个数存入字典树,然后查询就OK了。
我用原来自己写的大数模板一直超时,不知道为啥我的大数板子那么慢。。。只好手写个加法了
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5;
//Trie树
struct Trie
{
int id;
Trie *Next[10];
Trie()
{
id = -1;
for (int i = 0; i < 10; i++) Next[i] = NULL;
}
};
void Insert(Trie* root, string s, int id)
{
Trie* temp = root;
for (int i = 0; i < s.size(); i++)
{
int index = s[i] - '0';
if (temp->Next[index] == NULL)
{
temp->Next[index] = new Trie;
temp->Next[index]->id = id;
}
temp = temp->Next[index];
}
}
int Query(Trie* root, string s)
{
Trie *temp = root;
for (int i = 0; i < s.size(); i++)
{
int index = s[i] - '0';
if (temp->Next[index] == NULL) return -1;
temp = temp->Next[index];
}
return temp->id;
}
string add(string a, string b)
{
int i = a.size()-1, j = b.size()-1, g = 0;
string ans;
while (i >= 0 || j >= 0 || g)
{
int x = g;
if (i >= 0) x += (a[i] - '0');
if (j >= 0) x += (b[j] - '0');
g = x / 10;
ans += (x%10 + '0');
i--; j--;
}
reverse(ans.begin(), ans.end());
return ans;
}
int main()
{
Trie* root = new Trie;
string a = "1", b = "1";
Insert(root, "1", 0);
Insert(root, "1", 1);
for (int i = 2; i < MAXN; i++)
{
string sum = add(a, b);
a = b; b = sum;
if (sum.size() > 50) sum = sum.substr(0, 50);
Insert(root, sum, i);
}
int T, CASE = 1; scanf("%d", &T);
while (T--)
{
string str; cin >> str;
int ans = Query(root, str);
printf("Case #%d: %d\n", CASE++, ans);
}
return 0;
}
/*
15
1
12
123
1234
12345
9
98
987
9876
98765
89
32
51075176167176176176
347746739
5610
*/