• [Usaco2009 Feb]Bullcow 牡牛和牝牛


    原题链接https://www.lydsy.com/JudgeOnline/problem.php?id=3398

    容易想到的一种(dp)就是:设(dp[i][j])表示前(i)头牛里面有(j)头牡牛的方案数,那么转移方程就是:

    [dp[i][j]=dp[i-1][j]+dp[i-k][j-1] ]

    这里解释一下为什么是(dp[i-k][j-1])。因为dp数组存的是方案数,而如果第i头牛要是牡牛,那么(i-k)~(i-1)头牛都必须是牝牛,也就是只有这一种方案。但如果由(j-k)后面的状态转移过来,比如(j-k+1),那么根据方程,这个状态包含了第(j-k)头牛为牡牛的情况,这是不合法的情况。又因为(j-k)之前的牛是什么牛都无所谓,所以应该从(j-k)的状态转移过来。

    然后你发现这样开数组会爆空间,时间也会爆。然而我们发现,第i头牛是牡牛时,我们只需要知道第(i-k)头牛不是牡牛的方案数即可,与前面有几头牡牛无关。那么我们换一种状态,设(dp[i][0/1])表示第i头牛是牝牛/牡牛的方案数。转移方程类似:

    [dp[i][0]=dp[i-1][0]+dp[i-1][1];\ dp[i][1]=dp[i-k][0]; ]

    时间复杂度为(O(N))

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 100010
    #define mod 5000011
    using namespace std;
     
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
     
    long long dp[maxn][2];
    int n,k;
     
    int main(){
        n=read(),k=read();
        dp[0][0]=1;
        for(register int i=1;i<=n;i++){
            dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;
            dp[i][1]=dp[ max(0,i-k) ][0];
        }
        printf("%lld
    ",(dp[n][0]+dp[n][1])%mod);
        return 0;
    }
    
  • 相关阅读:
    三元表达式、列表推导式、生成器表达式、递归、匿名函数
    nonlocal关键字、装饰器
    函数嵌套、作用域、闭包
    实参和形参
    函数基础
    文件操作
    字符编码
    推荐一个纯JavaScript编写的图表库——Highcharts
    推荐web 前端代码的编辑分享平台——RunJS
    了解腾讯
  • 原文地址:https://www.cnblogs.com/akura/p/11310411.html
Copyright © 2020-2023  润新知