Revenge of Fibonacci

Revenge of Fibonacci


来源:UVA - 12333


题目描述:

The well-known Fibonacci sequence is defined as following:
F(0) = F(1) = 1
F(n) = F(n − 1) + F(n − 2) ∀n ≥ 2
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.


输入格式:

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.


输出格式:

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.


输入样例:

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

输出样例:

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

思路:

本题考查字典树Trie,字典树查询效率高,若用普通的查询方式,很可能会TLE。
首先构造字典树数据结构,用于存储斐波拉契数列序号小于100000的项。由于输入保证输入数字长度不超过40,故只需存储斐波拉契数列每项的数字的前45个即可,况且斐波拉契数列序号为100000的项数字长度达到了两万多,只存储前45个数字可以大大节省存储空间。
斐波拉契数列的每一项根据数字存储在字典树的每一个子节点上,并在子节点上存储第一个达到该节点的斐波拉契数列的这一项的序号。
若采用常规递推的思路去求解斐波拉契数列的每一项,随着斐波拉契数列后面项数字的增大,将会出现溢出情况。故用整形数组存储斐波拉契数列每一项的每一个数字,然后用加法递推的方式求解斐波拉契数列的每一项。
由于只要求存储斐波拉契数列每一项的前45个数字,故保持斐波拉契数列每一项的数字由高位数50位即可,不会影响结果的前40位数字。此方法可提升算法的时间性能。


AC代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

void __init__ ()
{
    // freopen("input.txt", "r", stdin);
    // freopen("output.txt", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
}

struct Node
{
    int id;
    Node* next[10];
    Node ()
    {
        id = -1;
        for (int i = 0; i < 10; i++) next[i] = NULL;
    }
};

const int maxn = 40 + 5, maxnn = 1e5;
Node* const root = new Node();
char s[maxn], fib[maxn];
int F[2][maxnn];

void add_Node (char* s, int id)
{
    Node* p = root;
    int len = strlen(s);
    for (int i = 0; i < len && i < maxn; i++)
    {
        int v = s[i] - '0';
        if (!p->next[v]) p->next[v] = new Node();
        p = p->next[v];
        if (-1 == p->id) p->id = id;
    }
}

void init ()
{
    F[0][0] = F[1][0] = 1;
    add_Node((char*)"1", 0);
    int start = 0, end = 1;
    for (int i = 2; i < maxnn; i++)
    {
        int p = i % 2, q = (i + 1) % 2;
        for (int j = start; j < end; j++) F[p][j] += F[q][j];
        for (int j = start; j < end; j++)
            if (F[p][j] >= 10)
            {
                F[p][j] %= 10;
                F[p][j + 1]++;
            }
        if (F[p][end]) end++;
        if (end - start > maxn + 5) start++;
        int r = end - 1, cnt = 0;
        memset(fib, '\0', sizeof(fib));
        while(r >= 0 && cnt < maxn) fib[cnt++] = F[p][r--] + '0';
        add_Node(fib, i);
    }
}

int query (char* s)
{
    Node* p = root;
    int len = strlen(s);
    for (int i = 0; i < len; i++)
    {
        p = p->next[s[i] - '0'];
        if (!p) return -1;
    }
    return p->id;
}

int main ()
{
    __init__();

    init();       
    int T;
    cin >> T;
    for (int i = 1; i <= T; i++)
    {
        cin >> s;
        cout << "Case #" << i << ": " << query(s) << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值