/*
参考:
http://www.cnblogs.com/kunsoft/p/5312726.html
收获:
1. 了解了字典树,可参考几个博客:
http://blog.csdn.net/u012469987/article/details/43874051
http://blog.csdn.net/u011787119/article/details/46991691
2.复习了常量指针和指向常量的指针
http://blog.csdn.net/luoweifu/article/details/45600415
3.复习了之前在看《挑战》时,只是略有了解的滚动数组
http://blog.csdn.net/u012577123/article/details/39211361
滚动数组最大的意义,在于缩减空间方面,对时间的影响不大
说明:
4.
关于 if(e - s > 50) ++s; 这句代码,一开始我一直不理解原因,也不明白为什么要取50,后来查阅了有关题解,才明白过来
因为要求精确到前40位,为了避免进位的误差,所以我们计算的时候,肯定要比40算的多一些(否则,如果真的取40,可能会有一些进位误差没有考虑到,例如有某个F数组的元素,算出来有进位,但是没有进行进位处理,如果这个错误的位置,恰好在我们需要的前40的精度里,那么就会WA了)
最后试验的结果时, e - s至少为49,当然,取200什么的也没问题,这个主要是代表了一个精度,让我们知道,我们求得的斐波拉契数列,大概有前多少位的范围,是精确可靠,可以相信的,所以往多了取当然没问题,但是不能取少了,所以最合适的是50、60的样子
另附上其他博客里的一些解释
4.1. 因为只是需要前40位,而且fibonacci数列上升速度很快, 所以我们保留60位的精度就足够了。
http://www.cnblogs.com/Jadon97/p/6922619.html
4.2. 因为只要前40位数字。所以在加的时候长度大于50左右就截掉个位上的,保留高位。
(这是我觉得最清楚而言简意赅的解释了,因为斐波拉契数可能会有很多位,所以我们要截断,可是只截断40位,可能有未处理的进位导致WA,所以我们截断前50位左右)
http://www.cnblogs.com/kuangbin/archive/2012/09/06/2673897.html
4.3.我们可以把斐波那契数列精确到50多位,然后只存40位即可,这样就防止进位的误差。在斐波那契数列加法过程中,我们只把它的前50多位进行相加,不然存不下。
http://blog.csdn.net/u012965373/article/details/40636371
*/
#include <bits/stdc++.h>
using namespace std;
struct Node
{
int id;
Node* next[10];
Node()
{
id = -1;
memset(next, 0, sizeof(next));
}
};
char Fib[50], In[50];
int F[2][1024000];
Node *const root = new Node();
void add_node (char* str, int id)
{
Node *u = root;
for (int i = 0, len = (int)strlen(str); i < len && i <= 40; i++)
{
int v = str[i] - '0';
if (!u->next[v])
u->next[v] = new Node();
u = u->next[v];
if (u->id == -1)
u->id = id;
//同一个长度n的斐波拉契数,截断为前1~i(1 <= i <= n)位以后,所有的截断方式,都具有相同的序号,表示以该字符串开头的斐波拉契数,对应的序号都是id
}
}
int query(char* str)
{
Node *u = root;
// 在树上顺序搜索str的每一个字符
for (size_t i = 0, len = strlen(str); i < len; i++)
{
u = u->next[str[i] - '0'];
// 若为空集,表示不存以此为前缀的斐波拉契序号
if (!u) return -1;
}
// 返回以该信息为前缀的斐波拉契序号
return u->id;
}
void init()
{
memset(F, 0, sizeof(F));
F[0][0] = F[1][0] = 1;
int s = 0, e = 1;
add_node((char *)"1", 0);
add_node((char *)"1", 1);
for(int i = 2; i < 100000; ++i)
{
int p = i%2, q = (i+1)%2;
for(int j = s; j < e; ++j)
F[p][j] = F[p][j] + F[q][j];
for(int j = s; j < e; ++j)
if(F[p][j]>=10)
{
F[p][j] %= 10;
F[p][j+1] += 1;
}
if(F[p][e]) ++e;
if(e - s > 50) ++s;
int r = e - 1, cnt = 0;
memset(Fib, 0, sizeof(Fib));
while(r >= 0 && cnt<40) //<40的限定,是因为输入不超过40个数字,因此初始化时,我们也只是取前40个数,若位数太多,有可能超过int的范围,导致运行错误(如果不对cnt做限定,则将RE)
Fib[cnt++] = F[p][r--] + '0';
add_node(Fib, i);
}
}
int main()
{
cin.tie(0);
cin.sync_with_stdio(false);
init();
int t;
cin >> t;
for (int i = 1; i <= t; i++)
{
cin >> In;
cout << "Case #" << i << ": " << query(In) << endl;
}
return 0;
}