zoukankan      html  css  js  c++  java
  • poj 3046 Ant Counting——多重集合的背包

    题目:http://poj.org/problem?id=3046

    多重集合的背包问题。

    1.式子:考虑dp[ i ][ j ]能从dp[ i-1 ][ k ](max(0 , j - c[ i ] ) <= k <= j)转移来。

      对于j<=c[ i ],这就是前缀和一样,所以dp[ i ][ j ] = dp[ i ][ j-1 ] + dp[ i-1 ][ j ];

      对于j>c[ i ],加了dp[ i ][ j-1 ] + dp[ i-1 ][ j ]之后会多加了一项dp[ i-1 ][ j-c[ i ]-1 ],减掉即可。

    2.意义:dp[ i-1 ][ j ]表示从前面组中选 j 个,dp[ i ][ j-1 ]表示从本组+前面组中选了 j-1 个,再在本组中选1个。

      有一个不合法的情况是dp[ i ][ j-1 ]中已经选了c[ i ]个本组的,就不能再在本组中选1个了。

      而 dp[ i ][ j-1 ]中已经选了c[ i ]个本组的 的方案数就是前面组中选了 j-1-c[ i ] 个的方案数(这样选 j-1 的时候就必须选c[ i ]个本组的了)。减掉即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=1005,M=1e5+5,mod=1e6;
    int n,m,c[N],l,r,dp[2][M],ans;
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&l,&r);int x;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&x);c[x]++;
        }
        dp[0][0]=dp[1][0]=1;
        for(int i=1;i<=n;i++)
        {
            int u=(i&1),v=!u;
            for(int j=1;j<=r;j++)
            {
                dp[u][j]=(dp[v][j]+dp[u][j-1])%mod;
                if(j>c[i])dp[u][j]=((dp[u][j]-dp[v][j-c[i]-1])%mod+mod)%mod;
            }
        }
        int u=(n&1);
        for(int j=l;j<=r;j++)(ans+=dp[u][j])%=mod;
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    软件工程导论P53,习题2.4
    视图和数据表的区别
    无法从“object”转换为“string”
    Oracle 密码重置
    Struts2 上传下载
    Spring 事务管理
    JSP 指令和动作
    JS 禁用回车、后退事件、form 表单不可编辑
    关于 in 和 exist 的理解
    Oracle clob 操作函数
  • 原文地址:https://www.cnblogs.com/Narh/p/9242268.html
Copyright © 2011-2022 走看看