HDU_4099_Revenge of Fibonacci_Trie树,高精度

今天得到铲神加持


题意:

给一串数字,长度不超过40,问fibonacci序列中第一个包含该前缀的数的编号是多少?如果在下标小于100 000的fibonacci数中找不到,就输出-1.



Input
  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.
 

Output
  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.


如果每次查询都遍历前100000个fibonacci数,必然超时,很自然想到用trie树来优化,先把前1000000个fibonacci数插进树里,每次查询即可。

fibonacci数是指数增长的,前100000个fibonacci数早就达到了十万位级别,全部存下显然不现实,题目只涉及前40个数字,我们只存储前五六十个数字,最后把每个数的前40个插进trie树,这几步优化都很重要。注意题目很可能注重实现,不要觉得只存储前五六十的数字可能会出错就不尝试,理论不是全部,测试才是真爱。运算完截取前60个数的时候要注意,之前的那个数应当也后退一位,留出前缀零(一位是由于是加法),这样在算下一个数字的时候才不会错位相加。

然后由于一直把编号为100000的数也插进去了,所以一直WA。。。

不过收获还是不小的,区域赛不限制内存,所以内存无所谓啦,然后HDU上没有使用过的静态内存不算在内存里面。。。。。。真心不知道这是为什么,于是就水过去了。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxp 10000000
#define mxl 65
struct bign{
	int a[mxl];
	int len;
	void init(int in){
		len=0;
		while(in){
			a[len++]=in%10;
			in/=10;
		}
	}
	bign operator + (bign& in){
		int pre=0;
		bign ret;
		ret.len=max(in.len,len);
		for(int i=0;i<ret.len;++i){
			int ta=0;
			int tb=0;
			if(i<len)	ta=a[i];
			if(i<in.len)	tb=in.a[i];
			int tem=ta+tb+pre;
			ret.a[i]=tem%10;
			pre=tem/10;
		}
		if(pre)	ret.a[ret.len++]=pre;
		if(ret.len>60){
			for(int i=0;i<60;++i)
				ret.a[i]=ret.a[ret.len+i-60];
			ret.len=60;
			if(pre){
				for(int i=0;i<59;++i)	in.a[i]=in.a[i+1];
				in.a[59]=0;
			}
		}
		return ret;
	}
};
int trie[mxp][10],cnt;
int idx[mxp];
void init(){
	cnt=0;
	memset(idx,-1,sizeof(idx));
	memset(trie[0],0,sizeof(trie[0]));
}
void insert(bign in,int num){
	int t=0;
	int c;
	int tem=0;
	for(int i=in.len-1;i>=0;--i){
		++tem;
		c=in.a[i];
		if(!trie[t][c]){
			trie[t][c]=++cnt;
			idx[cnt]=-1;
			memset(trie[cnt],0,sizeof(trie[cnt]));
		}
		t=trie[t][c];
		if(idx[t]==-1)	idx[t]=num;
		if(tem>41)	break;
	}
}
int find(char in[]){
	int len=strlen(in);
	int t=0;
	int c;
	for(int i=0;i<len;++i){
		c=in[i]-'0';
		if(!trie[t][c])	return -1;
		t=trie[t][c];
	}
	return idx[t];
}
bign a[3];
void setfib(){
	a[0].init(1);
	a[1].init(1);
	insert(a[0],0);
	insert(a[1],1);
	int now=0;
	for(int i=2;i<100000;++i){
		a[(now+2)%3]=a[now%3]+a[(now+1)%3];
		insert(a[(now+2)%3],i);
		++now;
	}
}
int main(){
	init() ;
	setfib();
	int cs,CS=0;
	scanf("%d",&cs);
	char read[50];
	while(cs--){
		scanf("%s",read);
		int ans=find(read);
		printf("Case #%d: %d\n",++CS,ans);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值