ZZ’s Fibonacci Problem
Describe:
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 first line contains an integer t — the number of tests (1≤t≤10). Each of the following t lines contains one test.
Each test is an integer n (1≤n≤10).
Output
For each input data test print a single number on a single line — the answer to the problem.
Sample:
Input: |
Output: |
2 13 16 |
3 4
|
解题思路:
首先,明确一点,任何数都可以由一个或多个斐波那契数组成;
由于斐波那契数的级数是非常大的,事实上到达__int64的斐波那契数将近在88个左右,所以预处理一下。
首先我们要先找出这样一种方案:方案中的最大的非波那且数 最大,为了保证在后面DP的时候不会漏掉一些情况。我们用一个特殊的二进制来表示我们刚刚得到的方案,
比如1000000100000001,二进制位为1 表示取了这个非波那且数(从左往右依次增大),那么一个1可以表示成左边两个1,001 ->110,那么某个1的表示方法就是cnt/2 ,
cnt为这个1与前面的1之间0的个数,所以总的方案数可以利用乘法原理从左往右递推过来,每个1 要么取,要么不取,取的话就只有一种方法,
不取的话就可以表示成中间若干个1的和,分两种情况转移即可.
1 #include <iostream> 2 #include <cstdio> 3 #include <iostream> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 int t; 9 long long n; 10 long long fib[90]; 11 long long b[90]; 12 long long dp[90][2]; 13 14 int main() 15 { 16 fib[0]=1; 17 fib[1]=1; 18 for(int i=2; i<=88; i++) 19 fib[i]=fib[i-1]+fib[i-2]; 20 while(scanf("%d",&t)!=EOF) 21 { 22 while(t--) 23 { 24 scanf("%lld",&n); 25 int k=1; 26 memset(b,0,sizeof(b)); 27 for(int i=88; i>=1; i--) 28 { 29 if(n>=fib[i]) 30 { 31 n-=fib[i]; 32 b[k++]=i; 33 } 34 } 35 reverse(b+1,b+k); 36 dp[1][1]=1; 37 dp[1][0]=(b[1]-1)/2; 38 for(int i=2; i<k; i++) 39 { 40 dp[i][1]=dp[i-1][0]+dp[i-1][1]; 41 dp[i][0]=(dp[i-1][0])*((b[i]-b[i-1])/2)+dp[i-1][1]*((b[i]-b[i-1]-1)/2); 42 } 43 printf("%lld\n",dp[k-1][0]+dp[k-1][1]); 44 } 45 46 } 47 return 0; 48 }