12333 - Revenge of Fibonacci

题目:给你一个数字串,判断他是哪一个Fib数的前缀,有多种答案输出最小的,不存在输出-1。

分析:字符串,大整数。

            首先,利用大整数计算Fib的前100000项,由于数据较大,只储存前50位即可。

            然后,按Fib的顺序存入字典树,利用滚动数组一边生成一边存储,可以减少内存开销。

                        在存的过程中直接进行标记,每个新节点直接标记成新加入的编号即标记路径。

                        这个值就表示到这个点结束的最小编号,这显然成立。

                        如果有更小的编号,应该更早早插入;而后面相同前缀的编号一定更大。

            最后,读入字符换,查询即可,无论是否是单词节点,直接返回记录的编号即可。


    #include <iostream>  
    #include <cstdlib>  
    #include <cstring>  
    #include <cstdio>  
      
    using namespace std;  
      
    /* Trie define */    
    #define nodesize 4000004      //节点个数     
    #define dictsize 10           //字符集大小     
        
    typedef struct node1    
    {  
        int    id;  
        int    flag;            //值域     
        node1* next[dictsize];    
    }tnode;    
    tnode  dict[nodesize];    
    int    ID[256];  
        
    class Trie    
    {    
        private:  
            int    size;    
            tnode* root;    
        public:    
            Trie() {makeID(); initial();}    
            void makeID() {    
                for ( int i = 0 ; i < 10 ; ++ i )    
                    ID['0'+i] = i;  
            }    
            void initial() {    
                memset( dict, 0, sizeof( dict ) );    
                root=NULL; size=0; root=newnode();    
            }    
            tnode* newnode() {return &dict[size ++];}    
            void insert( char* word, int L, int id ) {    
                tnode* now = root;    
                for ( int i = 0 ; i < L ; ++ i ) {  
                    if ( !now->next[ID[word[i]]] )    
                        now->next[ID[word[i]]] = newnode();    
                    /* 标记路径 */  
                    if ( !now->id && !now->flag ) now->id = id;  
                    now = now->next[ID[word[i]]];    
                }  
                if ( !now->flag ) {  
                    now->flag = 1;  
                    now->id = id;  
                }  
            }  
            int query( char* word ) {  
                tnode* now = root;    
                for ( int i = 0 ; word[i] ; ++ i ) {  
                    if ( !now->next[ID[word[i]]] ) return -1;    
                    now = now->next[ID[word[i]]];    
                }  
                return now->id;  
            }  
    }trie;    
    /* Trie  end */    
      
    int  F[2][21000];  
    char FF[42],In[42];  
      
    int main()  
    {  
        /* 大整数计算Fib前100000个数字 */  
        memset( F, 0, sizeof(F) );  
        F[0][0] = F[1][0] = 1;  
        trie.insert( "1", 1, 0 );  
        int s = 0,l = 1,r,count,p,q;  
        for ( int i = 2 ; i < 100000 ; ++ i ) {  
            p = i%2, q = (i+1)%2;  
            for ( int j = s ; j < l ; ++ j )  
                F[p][j] = F[p][j] + F[q][j];  
            for ( int j = s ; j < l ; ++ j )  
                if ( F[p][j] >= 10 ) {  
                    F[p][j+1] += 1;  
                    F[p][j]   -= 10;  
                }  
            if ( F[p][l] ) l ++;  
            if ( l - s > 50 ) s ++;  
            r = l-1;  count = 0;  
            while ( r >= 0 && count < 40 )   
                FF[count ++] = F[p][r --] + '0';  
      
            trie.insert( FF, count, i );  
        }  
        int T;  
        while ( scanf("%d",&T) != EOF )   
        for ( int t = 1 ; t <= T ; ++ t ) {  
            scanf("%s",In);  
            printf("Case #%d: %d\n",t,trie.query( In ));  
        }  
        return 0;  
    }  


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值