• [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('
    ');
    }
    
    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;
    }
    
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    struts2防止表单重复提交的解决方案
    从调试角度理解ActionContext、OgnlContext、OgnlValueStack的关系
    Struts2输入校验
    struts2异常处理机制
    struts2拦截器的实现原理及源码剖析
    设计模式六大原则(二):里氏替换原则
    设计模式六大原则(一):单一职责原则
    java中的对象、类、包、模块、组件、容器、框架、架构的概念入门
    jwt入门
    ubuntu18.04.2下编译openjdk9源码
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9139276.html
Copyright © 2020-2023  润新知