UVa 12333 - Revenge of Fibonacci

本文介绍了一种使用字典树(Trie)来高效处理大整数Fib数列前缀匹配的问题。通过存储Fib数列的前50位,并利用字典树的特性,可以快速查询给定数字串是否为某个Fib数的前缀,并返回最小的Fib数编号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:给你一个数字串,判断他是哪一个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;
}

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值