多校联合(4) ZZ’s Fibonacci Problem

题目链接:http://www.acmore.net/problem.php?id=1508

Stat

   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; 
} 


开始的时候没有考虑到输入数据的组数也是多重输入,就耽误了很多时间。

路途中。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值