UVa 12333 - Revenge of Fibonacci manweifc(模拟加法竖式 & 字典树)

题意:

给定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));
    }
}

 

 

转载于:https://www.cnblogs.com/Jadon97/p/6922619.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值