菲波拉契数制升级版
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
我们定义如下数列为菲波拉契数列:
F(1)=1 F(1)=1
F(2)=2 F(2)=2
F(i)=F(i−1)+F(i−2)(i>=3) F(i)=F(i−1)+F(i−2)(i>=3)
给定任意一个数,我们可以把它表示成若干互不相同的菲波拉契数之和。比如 13 13有三种表示法
13=13 13=13
13=5+8 13=5+8
13=2+3+8 13=2+3+8
现在给你一个数 n n,请输出把它表示成若干互不相同的菲波拉契数之和有多少种表示法。
Input
第一样一个数 T T,表示数据组数,之后 T T行,每行一个数 n n。
T≤105 T≤105
1≤n≤1018 1≤n≤1018
Output
输出 T T行,每行一个数,即 n n有多少种表示法。
Sample input and output
Sample Input | Sample Output |
---|---|
6 1 2 3 4 5 13 | 1 1 2 1 2 3 |
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<list>
#include<vector>
#include<iostream>
using namespace std;
typedef long long LL ;
vector<int>comb;
LL F[91],dp[91][2];
void init(){
F[0]=F[1]=1;
for(int i=2;i<=90;++i){
F[i]=F[i-1]+F[i-2];
}
}
void work(LL n){
comb.clear();
for(int i=90;i>=1;--i){
if(n>=F[i]){
n-=F[i];
comb.push_back(i-1);
}
}
sort(comb.begin(),comb.end());
dp[0][1]=1;
dp[0][0]=comb[0]/2;
for(int i=1;i<comb.size();++i){
dp[i][1]=dp[i-1][0]+dp[i-1][1];
dp[i][0]=(comb[i]-comb[i-1]-1)/2*dp[i-1][1]+(comb[i]-comb[i-1])/2*dp[i-1][0];
}
printf("%lld\n",dp[comb.size()-1][1]+dp[comb.size()-1][0]);
}
int main()
{
init();
int t;
LL n;
scanf("%d",&t);
while(t--){
scanf("%lld",&n);
work(n);
}
return 0;
}