51NOD 1350 斐波那契表示 规律+递归

题意:定义f(n)为:n最少需要用多少个fib数来表示. f(16)=2(16 =13+3 = 8+8)
定义g(n)=f(1)+f(2)+...f(n) Q次询问 每次给出一个n 求出g(n) n<=1e17.


先求f(n):每次用n减去当前最大的fib.
n很大 求g(n)时尝试打表:第i段 fib[i]个,则第i段的和w[i]=w[i-1]+(w[i-2]+f(i-2)).

n分解成若干段 最后一段只有x个 不满fib(i)时,可以将第i个区间不断分解 递归求解即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+5;
ll f[N],w[N],m=0;
void init()
{
	f[1]=f[2]=1;
	w[1]=w[2]=1;
	for(int i=3;;i++)
	{
		f[i]=f[i-1]+f[i-2];
		w[i]=w[i-1]+w[i-2]+f[i-2];
		if(f[i]>1e17)
			break;
	}
}
ll calc(ll i,ll x)
{
	if(x==f[i])
		return w[i];
	if(x<=f[i-1])
		return calc(i-1,x);
	//  f[i-1]<x<f[i]
	return w[i-1]+calc(i-2,x-f[i-1])+x-f[i-1];
}
int main()
{
	init();
	int T;
	cin>>T;
	while(T--)
	{
		ll n;
		scanf("%I64d",&n);
		ll id=0,sum=0,ans=0;
		while(sum+f[id+1]<n)
			sum+=f[++id];
		for(int i=1;i<=id;i++)
			ans+=w[i];
		ans+=calc(id+1,n-sum);
		printf("%I64d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值