zoukankan      html  css  js  c++  java
  • 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]);
    }

     

  • 相关阅读:
    计算机
    产品经理
    Vue router-link路由不同的写法,不一样的效果
    elementui样式引入方法
    格式化启动盘win10
    删除mongdb中的数据库
    google浏览器快速清除历史记录
    js动画之弹球打砖块小游戏
    js动画之面向对象二
    js动画之面向对象一
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8267443.html
Copyright © 2011-2022 走看看