zoukankan      html  css  js  c++  java
  • BZOJ.2660.[BJOI2012]最多的方案(DP)

    题目链接

    首先我们知道:
    1
    也很好理解。如果相邻两项出现在斐波那契表示法中,那它们显然可以合并。
    所以我们能得到(n)的斐波那契表示,记(pos[i])(n)的斐波那契表示法中,第(i)项在原斐波那契的下标,那么:(n=sum_{i=1}^{cnt}F[pos[i]])
    如果方案中不直接存在(F[pos[i]])(把(F[pos[i]])分解),那它只能由(<pos[i])的项构成。于是我们考虑递推。
    (f[i][1/0])表示当前考虑到(pos[i]),是/否分解(F[pos[i]]),且满足(F[pos[1]]sim F[pos[i]])都被组成,的方案数。

    如果不分解(F[pos[i]]),那么有$$f[i][0]=f[i-1][0]+f[i-1][1]$$,且(F[pos[i+1]])只能由([pos[i]+1,pos[i+1]])之间的项得到。

    如果分解(F[pos[i]]),则(F[pos[i+1]])可以由([pos[i],pos[i+1]])之间的项得到,而且若分解(F_i=F_{i-1}+F_{i-2}),下一次只能分解(F_{i-2}=F_{i-3}+F_{i-4}),再下一次只能分解(F_{i-4}=ldotsldots)。于是我们可以得到在区间([l,r-1])中分解(F_r)的方案数为(frac{r-l}{2})
    于是可以得到:$$f[i][1]=f[i-1][0] imesfrac{pos_i-pos_{i-1}-1}{2}+f[i-1][1] imesfrac{pos_i-pos_{i-1}}{2}$$

    初始值就是(f[1][0]=1,f[1][1]=frac{pos_i-1}{2})

    另外直接map记搜也能跑得飞快(甚至比递推快smg。。)

    #include <cstdio>
    #include <algorithm>
    typedef long long LL;
    const int N=100;
    
    int p[N],f[N][2];
    LL n,F[N];
    
    int main()
    {
    	scanf("%lld",&n);
    	F[1]=1, F[2]=2; int t,cnt=0;
    	for(t=3; (F[t]=F[t-1]+F[t-2])<=n; ++t);
    	for(int i=t; i; --i)
    		if(n>=F[i]) n-=F[i], p[++cnt]=i;
    	std::reverse(p+1,p+1+cnt);
    
    	f[1][0]=1, f[1][1]=p[1]-1>>1;
    	for(int i=2; i<=cnt; ++i)
    		f[i][0]=f[i-1][0]+f[i-1][1],
    		f[i][1]=f[i-1][0]*(p[i]-p[i-1]-1>>1)+f[i-1][1]*(p[i]-p[i-1]>>1);
    	printf("%d
    ",f[cnt][0]+f[cnt][1]);
    
    	return 0;
    }
    
  • 相关阅读:
    【Linux常用命令】 cat
    【Linux常用命令】 chmod
    【2012.4.22】北京植物园&卧佛寺
    【Linux常用命令】 重定向输出 > 和 >>
    一些话
    linux下查看用户个数和具体名字
    【Linux常用命令】 ls
    Ethernet frame
    防止修改类和方法
    redis数据批量导入导出
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9667017.html
Copyright © 2011-2022 走看看