题意:
给定n个(n<=40)数字, 求100000个以内有没有前面n个数字符合给定的数字的fibonacci项, 如果有, 给出最小的fibonacci项, 如果没有, 输出-1。
分析:
可以将这个问题分为两个部分:
①求出10万个fibonacci数列的前40个数字
②查找给定的数在不在这些数字里面
对于第一个部分, 我们可以模拟竖式加法(可以用滚动数组节省内存), 然后因为只是需要前40位,而且fibonacci数列上升速度很快, 所以我们保留60位的精度就足够了。
对于第二部分,可以构造字典树,用数组模拟可以避免指针带来的不必要出错。
#include <bits/stdc++.h> using namespace std; struct Node { int id; int next[10]; Node(){ id = -1; for(int i = 0; i < 10; i++) { next[i] = -1; } } }; Node trie[4266670]; int cnt = 0; const Node root = trie[cnt++]; void add_node(const char str[], int id) { int index = 0; for(int i = 0, len = strlen(str); i < len; i++) { int v = str[i] - '0'; if((trie[index].next[v] == -1)) { trie[index].next[v] = cnt; index = cnt; cnt++; } else { index = trie[index].next[v];//如果存在直接去到下一个节点 } if(trie[index].id == -1){ trie[index].id = id; } } } int Find(const char str[]) { int index = 0; for(int i = 0, len = strlen(str); i < len; i++) { int v = str[i] - '0'; if(v < 0) return -1; if(trie[index].next[v] == -1) { return -1; } index = trie[index].next[v]; } return trie[index].id; } int main() { char t[50]; memset(t,0,sizeof(t)); int fib[2][30000]; add_node((char*)"1",0); int p, q, s, l; s = 0; l = 1; fib[0][0] = 1; fib[1][0] = 1; for(int f = 2; f < 100000; f++){ p = f&1, q = (f+1) &1; //滚动数组 for(int i = s; i < l; i++){ fib[p][i] = fib[p][i] + fib[q][i]; if(fib[p][i] >= 10){ fib[p][i+1]++; fib[p][i] -= 10;//进位了记得要减回来 if(i == l-1){ l++;//如果最后一位还要进位 那么位数+1 } } } if(l - s > 60) s++;//保留前60位的精度 int cnt = 0; for(int i = l - 1; i >= s && cnt < 40; i--) { t[l-i-1] = fib[p][i]+'0'; cnt++; } add_node((char*)t,f);//截取前40个数字构造字典树 memset(t,0,sizeof(t)); } int tt; scanf("%d", &tt); int kase = 1; char que[50]; while(tt--) { scanf("%s", que); printf("Case #%d: %d\n",kase++, Find(que)); } }