bzoj千题计划213:bzoj2660: [Beijing wc2012]最多的方案

Posted 日拱一卒 功不唐捐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj千题计划213:bzoj2660: [Beijing wc2012]最多的方案相关的知识,希望对你有一定的参考价值。

http://www.lydsy.com/JudgeOnline/problem.php?id=2660

 

很容易想到是先把n表示成最大的两个斐波那契数相加,然后再拆分这两个斐波那契数

把数表示成斐波那契进制的形式,第i位表示有没有第i个斐波那契数

比如16=13+3     001001

那么拆分一个数就是把一个1变成0,左边的两个0变成1

前面的1不影响后面

后面1拆出的两个1不能拆到前面1的前面

所以b[i] 表示n的第i个1是第几项斐波那契数

所以dp[i][0/1] 表示b中的i所在位(n的第b[i]个1)是0/1的方案数

如果这个位是1,dp[i][0]=dp[i-1][0]+dp[i-1][1]

如果这个位是0,即这个1被拆了,他能拆的次数是 与前面的1之间的0的个数/2

所以若i-1是1,两个1之间有 b[i]-b[i-1]-1个0

若i-1是0,两个1之间有b[i]-b[i-1]个0

dp[i][1]=dp[i-1][1]*(b[i]-b[i-1]-1)/2+dp[i-1][0]*(b[i]-b[i-1])/2

 

#include<cstdio>
#include<algorithm>

typedef long long LL;

using namespace  std;

LL f[101];

int b[101];

LL dp[101][2]; 

int main()
{
    LL n;
    scanf("%lld",&n);
    f[1]=1; f[2]=2;
    int t;
    for(t=3;f[t-1]+f[t-2]<=n;++t) f[t]=f[t-1]+f[t-2];
    int m=0;
    for(int i=t-1;i;--i)
        if(n>=f[i]) b[++m]=i,n-=f[i];
    reverse(b+1,b+m+1);
    dp[1][1]=1;
    dp[1][0]=b[1]-1>>1;
    for(int i=2;i<=m;++i)
    {
        dp[i][1]=dp[i-1][0]+dp[i-1][1];
        dp[i][0]=dp[i-1][1]*(b[i]-b[i-1]-1>>1)+dp[i-1][0]*(b[i]-b[i-1]>>1);
    }
    printf("%lld",dp[m][0]+dp[m][1]);
}

 

 

以上是关于bzoj千题计划213:bzoj2660: [Beijing wc2012]最多的方案的主要内容,如果未能解决你的问题,请参考以下文章

bzoj千题计划197:bzoj4247: 挂饰

bzoj千题计划118:bzoj1028: [JSOI2007]麻将

bzoj千题计划165:bzoj5127: 数据校验

bzoj千题计划144:bzoj1176: [Balkan2007]Mokia

bzoj千题计划177:bzoj1858: [Scoi2010]序列操作

bzoj千题计划142:bzoj3144: [Hnoi2013]切糕