Revenge of Fibonacci UVA - 12333
链接;https://vjudge.net/problem/UVA-12333
这题又做崩了,一开始看紫书以为写个高精再暴力枚举就能过,然后就一直TLE。。最后找了下udebug上的数据,发现一旦访问多了运行时间就爆了。最后用map存储前缀和对应的下标的集合来缩小枚举范围过了。不过后来发现这题正解是字典树。
其实一开始想过用字典树存储前缀,但我计算空间的时候以为是10的40次方,心想这不是要爆炸吗,,就觉得行不通。后来才想清楚正确的算法应该是fib数的个数10000 * 40。也就是字典树的空间要开到存储的字符串的总长度。我太菜了。。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <ctime> #include <unordered_map> #include <map> #include <set> #define mod 100000000 #define DLEN 8 //#define fre //#define DEBUG using namespace std; unordered_map<string, set<int> > pre; struct Bigint { vector<int> a = {1}; int len = 1; void add (const Bigint& b, Bigint& res, int id) { res.len = max(len, b.len); res.a.resize(res.len + 1); for (int i = 0; i <= res.len; ++i) res.a[i] = 0; for (int i = 0; i < res.len; ++i) { res.a[i] += (i < len ? a[i] : 0) + (i < b.len ? b.a[i] : 0); res.a[i + 1] += res.a[i] / mod; res.a[i] %= mod; } if (res.a[res.len] > 0) res.len++; string now = to_string(res.a[res.len - 1]), now2 = now; int base = 10000000; //固定存8位以内的前缀 while (now2.length() > 0) pre[now2].insert(id), now2 = now2.substr(0, now2.length() - 1); while (res.len >= 2 && now.length() <= 8) pre[now].insert(id), now += char(res.a[res.len - 2] % (base * 10) / base + '0'), base /= 10; } bool isprefix(const string& s) { int firlen = 1, base = 10; while (a[len - 1] / base) ++firlen, base *= 10; if ((len - 1) * DLEN + firlen < s.length()) return false; base /= 10; if (firlen >= s.length()) { for (int i = 0; i < s.length(); ++i) { if (a[len - 1] % (base * 10) / base != s[i] - '0') return false; base /= 10; } return true; } else { int i; for (i = 0; i < firlen; ++i) { if (a[len - 1] % (base * 10) / base != s[i] - '0') return false; base /= 10; } int curlen = len - 1; base = 10000000; for(;;curlen--, base = 10000000) { for (int j = 0; j < DLEN; ++j, ++i) { if (i == s.length()) return true; if (a[curlen - 1] % (base * 10) / base != s[i] - '0') return false; base /= 10; } } } } } fib[100000]; int main() { #ifdef fre freopen("in.in", "r", stdin); freopen("out.txt", "w", stdout); #endif pre["1"].insert(0); for (int i = 2; i < 100000; ++i) { fib[i - 2].add(fib[i - 1], fib[i], i); } #ifdef DEBUG printf("time used %.2f\n", double(clock()) / CLOCKS_PER_SEC); #endif string s; int t, cur; bool f; scanf("%d", &t); for (int ind = 1; ind <= t; ++ind) { printf("Case #%d: ", ind); f = false; cin >> s; if (s == "0") { printf("-1\n"); continue; } if (s.length() >= 8) cur = 8; else cur = s.length(); if (pre.count(s.substr(0, cur))) { for (auto& id : pre[s.substr(0, cur)]) { if (fib[id].isprefix(s)) { f = true; printf("%d", id); break; } } } if (!f) printf("-1"); cout << endl; } #ifdef DEBUG printf("time used %.2f\n", double(clock()) / CLOCKS_PER_SEC); #endif }