BZOJ2660: [Beijing wc2012]最多的方案

138 篇文章 0 订阅

样例解释我没看我也不知道看了能不能秒qaq,反正我不会做,我觉得还是挺厉害的呀…

先从大到小枚举fib数,不比n大就添加进集合, 得到一个fib数最大的分解,因为没有重复的数,我们用一个01串表示一个n的fib分解,如果分解出的数有这个fib数这一位就为1否则为0
假如我们写出了这样一个串 0011000101000111

感受一下就发现n的所有分解都一定是这个串里面的1拆成2个铺在左边这样弄成的
然后用归纳法可证,连着的两个11,第二个1是不能拆的,可以忽略掉他们,变成0010001010001这样
一个1向左拆,拆完一次后产生了11这样的东西,那右边那个1又是不能拆的
所以我们可以分段考虑
f[i][0/1]表示第i段有没有拆的方案数
一个简单的dp

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 110;

ll n;
ll F[maxn];
int s[maxn],f[maxn];
ll g[2];

int main()
{
    F[0]=F[1]=1; for(int i=2;i<=89;i++) F[i]=F[i-1]+F[i-2];
    f[1]=f[2]=0; for(int i=3;i<=89;i++) f[i]=f[i-2]+1;

    scanf("%lld",&n);
    for(int i=89;i>=1;i--)
        if(n>=F[i]) n-=F[i],s[i]=1;
    if(n) return puts("0"),0;

    int la=0; g[0]=0,g[1]=1;
    for(int i=1;i<=89;i++) if(s[i])
    {
        ll g0,g1;
        g0=g[1]*f[i-la]+g[0]*f[i-la+1];
        g1=g[0]+g[1];
        g[0]=g0;
        g[1]=g1;
        la=i;
    }
    printf("%lld\n",g[0]+g[1]);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值