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
}

 

posted @ 2020-02-04 14:37  JonKitten  阅读(156)  评论(0编辑  收藏  举报