题意:定义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)).
定义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;
}