题目链接:http://www.acmore.net/problem.php?id=1508
ZZ is a big fan of Fibonacci numbers, and she pays lots of attention on Fibonacci numbers, Fibonacci numbers have the following form: F(1) = 1, F(2) =2, F(i) = F(i-1) + F(i-2), i > 2. ZZ is a so clever girl, she found some interested things, a non-empty set S = { s1,s2……sk }, consisting of different Fibonacci numbers, the sum of this set’s elements call the set S a number n’s decomposition into Fibonacci sum. It’s easy to see that the numbers have several decompositions into Fibonacci sum, for example, for 13 we have 13, 5 + 8, 2 + 3 + 8 three decomposition, and for 16,3 +13, 1 + 2 +13 , 3 + 5 + 8, 1 + 2 + 5 + 8 --- four decompositions . ZZ is so happy of find this, but what's a pity, ZZ don’t know how to find the number of the possible different decompositions into Fibonacci sum if give a number n ? Can you help her?
Input
The input contains several test cases,The first line of each test case consists of an integer t — the number of tests (1≤t≤105),next t lines contain an integer n (1≤n≤1018).
Output
For each input data test print a single number on a single line — the answer to the problem.
Sample Input
2 13 16
Sample Output
3 4
题意:
给一个数字x, x<=1e18, 求其分解成数个fib数相加的方案总数.其中fib数不能重复.
解题思路:
首先一个结论: 任意一个数,都能被分解成 数个fib数相加的形式.
另外, 在区间 [1,1e18]总共有 88个fib数.
对于一个数 x, 我们用一个长度为88的01序列来唯一表示.当前位为1则表示取,否则不取
例如 8: 00000100...0 2: 00100...0 3: 0110...0 从高位到低位.
根据 fib_i = fib_i-1 + fib_i-2 .
对于一个序列 001, 其能够被 110 替换. 我们可以总结出. 当前位为1,若其前面有两个0,则可被替换.
2个0替换一个1, 如此连续. 则若 i为1,其后面有cnt个0, 则其方案数为 cnt/2 (计算机整除,2位为1方案)
另外我们用一个数组来表示状态:
dp( i, j ) , 表示第 a[i]位为1时, j = 0,表示不取, j = 1表示取的 方案数.
j = 1 若当前位取, 则只有中方案, 则其可能是由前一位取或者不取而来.所以有:
dp( i, 1 ) = dp( i-1, 0 ) + dp( i-1, 1 )
j= 0 若当前位不取,
当其为 前一位取而来时, i前面则有 bi - bi-1 个空格, 所以方案数是 ( b_i - b_(i-1) )/2
dp( i, j ) = dp( i-1, 0 ) * ( ( b_i - b_(i-1) )/2 ) //注意整除.
当其为 前一位不取而来时,则i前面的0位增加一个,总数为 b_i - b_(i-1) + 1,所以方案数是 (b_i-b_(i-1)+1)/2
dp( i, j ) = dp( i-1, 1 ) *( (b_i - b_(i-1) + 1) /2 )
AC代码:
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL n,q[108];
int a,i,j;
int main()
{
int dp[108][2],w[90];
q[0]=q[1]=1;
for(i=2;i<87;i++){
q[i]=q[i-1]+q[i-2];
}
int t;
while(~scanf("%d",&t))
{
while(t--){
memset(dp,0,sizeof(dp));
memset(w,0,sizeof(w));
scanf("%lld",&n);
a=1;
for(i=86;i>0;i--)
{
if(n-q[i]>=0)
{
n-=q[i];
w[a++]=i;
}
}
sort(w+1,w+a);
dp[0][1]=1;
for(i=1;i<a;i++){
dp[i][1]=dp[i-1][0]+dp[i-1][1];
dp[i][0]=dp[i-1][1]*((w[i]-w[i-1]-1)/2)+dp[i-1][0]*((w[i]-w[i-1])/2);
}
printf("%d\n",dp[a-1][0]+dp[a-1][1]);
}
}
return 0;
}
开始的时候没有考虑到输入数据的组数也是多重输入,就耽误了很多时间。
路途中。。。。。