hdu 4099 Revenge of Fibonacci

Problem Description
The well-known Fibonacci sequence is defined as following:

Here we regard n as the index of the Fibonacci number F(n).
This sequence has been studied since the publication of Fibonacci’s book Liber Abaci. So far, many properties of this sequence have been introduced.
You had been interested in this sequence, while after reading lots of papers about it. You think there’s no need to research in it anymore because of the lack of its unrevealed properties. Yesterday, you decided to study some other sequences like Lucas sequence instead.
Fibonacci came into your dream last night. “Stupid human beings. Lots of important properties of Fibonacci sequence have not been studied by anyone, for example, from the Fibonacci number 347746739…”
You woke up and couldn’t remember the whole number except the first few digits Fibonacci told you. You decided to write a program to find this number out in order to continue your research on Fibonacci sequence.

Input
There are multiple test cases. The first line of input contains a single integer T denoting the number of test cases (T<=50000).
For each test case, there is a single line containing one non-empty string made up of at most 40 digits. And there won’t be any unnecessary leading zeroes.

Output
For each test case, output the smallest index of the smallest Fibonacci number whose decimal notation begins with the given digits. If no Fibonacci number with index smaller than 100000 satisfy that condition, output -1 instead – you think what Fibonacci wants to told you beyonds your ability.

Sample Input
15
1
12
123
1234
12345
9
98
987
9876
98765
89
32
51075176167176176176
347746739
5610

Sample Output
Case #1: 0
Case #2: 25
Case #3: 226
Case #4: 1628
Case #5: 49516
Case #6: 15
Case #7: 15
Case #8: 15
Case #9: 43764
Case #10: 49750
Case #11: 10
Case #12: 51
Case #13: -1
Case #14: 1233
Case #15: 22374

题意:

题面一阵瞎扯之后,可以发现意思是:给一个数字,求以此为前缀的斐波那契数的标号的最小值。

思路:

查询前缀,很容易想到字典树,然而难的是大整数加法(对蒟蒻来说)和一些细节。

细节:1smaller than 指的是严格小于,标号等于1e5的数是不能放到字典树里的。2f[0] = 1,f[1] = 1,f[2] = 2,初始值的标号比正常的小一位,而且题目里的图不见了,只能从样例看出。

大整数加法:首先暴力打了一个高精度板子,在十数秒的运行之后,发现第1e5个fibonacci数长度有2e4左右,暴力算要TLE,于是(看了一波题解)把位数改成了50位,也就是大整数只保留前50位,因为题目输入的前缀最长只有40,所以后面的几乎是不需要的,留几位给他进位就好了。于是在此又打萎了,在长度超过50的时候,傻傻地把超过50位的除以10,和一个原本就只有50位的加起来了。调这个智障错误调了很久,还对着表一个一个对。。。其实只要求出一个超过50的数,就把前一位和他都除以10就没有问题了。

最后要注意:我的高精喜欢用+=,-=,%=这种运算符,所以在每次运算之前,要考虑原来的大整数有没有初始化,曾经因为这个出过很多错。

最近打了几个要高精度的题,比如高精GCD,在感叹PYthon的强大之余,还是觉得自己需要多练习程序实现,板子要会灵活运用才行。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
const int N = 1e5;
const int M = 55;
struct NUM{
    int len, a[M];
    NUM operator = (string s){
        len = s.size();
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= len; i++)
            a[i] = s[len-i]-'0';
        return *this;
    }
    NUM operator + (NUM x){
        NUM y;
        memset(y.a, 0, sizeof(y.a));
        y.len = max(len, x.len);
        for (int i = 1; i <= y.len; i++){
            y.a[i] += a[i]+x.a[i];
            y.a[i+1] += y.a[i]/10;
            y.a[i] %= 10;
        }
        if (y.a[y.len+1] > 0) y.len++;
        return y;
    }
    void Rightshift(){
        for (int i = 1; i < len; i++)
            a[i] = a[i+1];
        a[len--] = 0;
    }
}a[3];
struct TRIE{
    int son[10], ed;
    void clear(){
        memset(son, 0, sizeof(son));
        ed = N+10;
    }
}trie[N*45];
int tot;

void Insert(NUM x, int idx)
{
    int len = x.len, now = 0, val;
    for (int i = len; i >= max(1, len-39); i--){
        val = x.a[i];
        if (trie[now].son[val] == 0)
            trie[now].son[val] = ++tot, trie[tot].clear();
        now = trie[now].son[val];
    }
    trie[now].ed = min(trie[now].ed, idx);
}

void Dfs(int now)
{
    for (int i = 0; i < 10; i++)
        if (trie[now].son[i]){
            Dfs(trie[now].son[i]);
            trie[now].ed = min(trie[now].ed, trie[trie[now].son[i]].ed);
        }
}

int Search(NUM x)
{
    int len = x.len, now = 0, val;
    for (int i = len; i >= max(1, len-41); i--){
        val = x.a[i];
        if (trie[now].son[val] == 0)
            return -1;
        now = trie[now].son[val];
    }
    return trie[now].ed;
}

int main()
{
    a[1] = a[0] = "1";
    tot = 0;
    Insert(a[1], 0);
    for (int i = 2; i < N; i++){
        int now = i%3, p1 = (i+1)%3, p2 = (i+2)%3;
        a[now] = a[p1]+a[p2];
        if (a[now].len > 50){
            a[now].Rightshift();
            a[p1].Rightshift();
            a[p2].Rightshift();
        }
        Insert(a[now], i);
    }
    Dfs(0);
    int n;
    while (scanf("%d", &n) == 1){
        for (int i = 1; i <= n; i++){
            string s; cin >> s;
            NUM x; x = s;
            printf("Case #%d: %d\n", i, Search(x));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyyxyyx/article/details/81672135