[luogu4133 BJOI2012] 最多的方案 (计数dp)

[luogu4133 BJOI2012] 最多的方案 (计数dp)

题目描述

第二关和很出名的斐波那契数列有关,地球上的OIer都知道:F1=1, F2=2, Fi = Fi-1 + Fi-2,每一项都可以称为斐波那契数。现在给一个正整数N,它可以写成一些斐波那契数的和的形式。如果我们要求不同的方案中不能有相同的斐波那契数,那么对一个N最多可以写出多少种方案呢?

输入输出格式

输入格式:
只有一个整数N。

输出格式:
一个方案数

输入输出样例

输入样例#1: 复制
16
输出样例#1: 复制
4
说明
Hint:16=3+13=3+5+8=1+2+13=1+2+5+8

对于30%的数据,n<=256

对于100%的数据,n<=10^18

首先需要知道的是任何一个自然数可以像这样被斐波那契数分解
我们又知道n>=3时斐波那契数可以被前两个数的和替换
那么我们可以先贪心找到一种每个数最大的方案
然后尝试将其中的数替换,使用dp计数
f[i][1/0] 表示最大分解中的第i个是否被替换(0表示被替换)
得到动规方程:

f[i][1]=f[i-1][1]+f[i-1][0];
f[i][0]=f[i-1][0]*(pos[i]-pos[i-1])/2 +
            f[i-1][1]*(pos[i]-pos[i-1]-1)/2;
    //ps:当该数(pos[i])要分解时考虑pos[i-1]能否使用
//即若pos[i-1]被替换(f[i-1][0])则可使用,若没替换则不行(-1即可)

code:

//By Menteur_Hxy
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include <ctime>
#define M(a,b) memset(a,(b),sizeof(a))
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define LL long long
using namespace std;

inline LL rd() {
    LL x=0,fla=1; char c=' ';
    while(c>'9'|| c<'0') {if(c=='-') fla=-fla; c=getchar();}
    while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
    return x*fla;
}

inline void out(LL x){
    int a[25],wei=0;
    if(x<0) putchar('-'),x=-x;
    for(;x;x/=10) a[++wei]=x%10;
    if(wei==0){ puts("0"); return;}
    for(int j=wei;j>=1;--j) putchar('0'+a[j]);
    putchar('\n');
}

const int MAX=1010;
const int INF=0x3f3f3f3f;
LL n,cnt,scnt;
LL f[MAX][2],fib[MAX],pos[MAX];

int main() {
    n=rd();
    fib[1]=1,fib[2]=2;
    for(cnt=3;fib[cnt-1]<=n;cnt++) fib[cnt]=fib[cnt-1]+fib[cnt-2];
    cnt--;
    for(int i=cnt;i>=1;i--) if(n>=fib[i]) {
        n-=fib[i]; pos[++scnt]=i;
    }
    sort(pos+1,pos+scnt+1);
    f[1][1]=1; f[1][0]=((pos[1]-1)>>1);
    F(i,2,scnt) {
        f[i][1]=f[i-1][0]+f[i-1][1];
        f[i][0]=f[i-1][0]*(pos[i]-pos[i-1]>>1) + f[i-1][1]*(pos[i]-pos[i-1]-1>>1);
    }
    out(f[scnt][0]+f[scnt][1]);
    return 0;
}
posted @ 2018-06-05 13:19 Menteur_Hxy 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值