HDU 4099/UVA 12333 Revenge of Fibonacci

67 篇文章 0 订阅

hdu题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4099


题意:给出一个不超过40长度的前缀,在前10W项fib项数中查找最小满足前缀的项数。


思路:因为fib数列增长很快,而且查询长度不超过40,我们可以考虑用高精度计算然后用字典树维护每一项的前40位。
大概计算55位长度就够了(因为取前40位,后面造成的误差不影响前40位的计算),因为每次加的时候最多进一位,所以进位的时候都要向后移,保证加法的时候数位对齐。


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long

//**************trie
struct trie
{
    trie *next[10];
    int last;

};
trie *root;
void init(trie *x)
{
    rep(i,0,9) x->next[i] = NULL;
    x->last = 111111;
}

void insert(trie *x,int a[],int pos,int k)
{
    int num = 0;
    while( pos && num<40 )
    {
        if ( x->next[a[pos]] == NULL )
        {
            x->next[a[pos]] = new trie;
            init(x->next[a[pos]]);
            x->next[a[pos]]->last = k;
        }
        x = x->next[a[pos]];
        pos--;
        num++;
    }
}
int query(char s[])
{
    trie *p = root;
    int len = strlen(s);
    rep(i,0,len-1)
    {
        int index = s[i] - '0';
        if ( p->next[index] == NULL ) return -1;
        p = p->next[index];
    }
    if ( p->last == 111111 ) return -1;
    return p->last;
}
//**************trie
void Init()
{
    root = new trie;
    init(root);
    int a[4][100];
    Clean(a,0);
    a[0][0] = a[0][1] = 1;
    a[1][0] = a[1][1] = 1;
    insert(root,a[0],1,0);
    int k1,k2,k3;
    int k,l;
    rep(j,2,99999)
    {
        k = 0;
        l = 55;
        k1 = j % 3;
        k2 = ( k1 + 1 ) % 3;
        k3 = ( k2 + 1 ) % 3;
        Clean(a[3],0);
        Clean(a[k1],0);
        rep(i,1,55)
        {
            a[3][i] += a[k2][i] + a[k3][i];
            if ( a[3][i] >= 10 )
            {
                a[3][i] -= 10;
                a[3][i+1]++;
            }
        }
        if ( a[3][56] )
        {
            k = 1;
            rep(i,1,a[k2][0]) a[k2][i] = a[k2][i+1];
            rep(i,1,a[k3][0]) a[k3][i] = a[k3][i+1];
        }
        rep(i,1,55) a[k1][i] = a[3][i+k];
        while( !a[k1][l] ) l--;
        a[k1][0] = l;
        insert(root,a[k1],l,j);
    }
}

int main()
{
    Init();
    char t[50];
    int T;
    cin>>T;
    getchar();
    rep(i,1,T)
    {
        gets(t);
        printf("Case #%d: %d\n",i,query(t));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值