Ant Counting POJ - 3046【dp-多重集组合数-模板】

题意简述:有t种蚂蚁 ,a个蚂蚁 每个蚂蚁属于一个种类 不同类蚂蚁可以区分 同类蚂蚁不可以区分 求这些蚂蚁组成大小为s s+1…b集合的组合数


多重集组合数模板

n种物品,第i种物品有ai个,不同种类物品可以互相区分但是相同种类无法区分。从这些物品中取出m个,求方案数。
Ant Counting POJ - 3046【dp-多重集组合数-模板】_第1张图片

——方法来源于《挑战程序设计竞赛》P68-69
注意这里的物品种类编号是从0~n-1的


Code View

#include
#include
#include
#include
using namespace std;
#define LL long long
#define MAXN 1005
#define INF 0x3f3f3f3f
#define MOD 1000000
int dp[MAXN][MAXN*10];//dp[i+1][j] 前i种物品中取j个
/*
dp[i+1][j]=sigma dp[i][j-k]|0<=k<=min(j,a[i])

dp[i+1][j-1]=sigma dp[i][j-1-k] |0<=k<=min(j-1,a[i])
sigma dp[i][j-k] =dp[i][j]+dp[i][j-1]+dp[i][j-2]+···+dp[i][j-a[i]]
sigma dp[i][j-1-k]=dp[i][j-1]+dp[i][j-2]+···+dp[i][j-1-a[i]]sigma dp[i][j-k]=sigma dp[i][j-1-k]+dp[i][j]-dp[i][j-1-a[i]]
进行代换 dp[i+1][j]=dp[i+1][j-1]+dp[i][j]-dp[i][j-1-a[i]]

*/
int n,tot,s,b;
int a[MAXN];
int main()  
{
    scanf("%d %d %d %d",&n,&tot,&s,&b);
    for(int i=1;i<=tot;i++)
    {
        int tmp;
        scanf("%d",&tmp);
        a[tmp-1]++;
    }
    for(int i=0;i<=n;i++)
        dp[i][0]=1;
    for(int i=0;i
        for(int j=1;j<=b;j++)
            if(j-1-min(j,a[i])>=0)
                dp[i+1][j]=(dp[i+1][j-1]+dp[i][j]-dp[i][j-1-min(j,a[i])]+MOD)%MOD;
            else dp[i+1][j]=(dp[i+1][j-1]+dp[i][j])%MOD;             
    int ans=0; 
    for(int i=s;i<=b;i++)
        ans=(dp[n][i]+ans)%MOD;
    printf("%d\n",ans);
    return 0;
}

后话
书上的定义和我平时用惯的不太一样,因为书上的a数组是从0~n-1
我还是觉得 dp[i+1][j]的定义方式有点strange
我个人比较习惯dp[i][j]:前i种物品中取j个
然后自己试了一下

AC code

#include
#include
#include
#include
using namespace std;
#define LL long long
#define MAXN 1005
#define INF 0x3f3f3f3f
#define MOD 1000000
int dp[MAXN][MAXN*10];
int n,tot,s,b;
int a[MAXN];
int main()  
{
    scanf("%d %d %d %d",&n,&tot,&s,&b);
    for(int i=1;i<=tot;i++)
    {
        int tmp;
        scanf("%d",&tmp);
        a[tmp]++;
    }
    for(int i=0;i<=n;i++)
        dp[i][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=b;j++)
            if(j-1-min(j,a[i])>=0)
                dp[i][j]=(dp[i][j-1]+dp[i-1][j]-dp[i-1][j-1-min(j,a[i])]+MOD)%MOD;
            else dp[i][j]=(dp[i][j-1]+dp[i-1][j])%MOD;             
    int ans=0; 
    for(int i=s;i<=b;i++)
        ans=(dp[n][i]+ans)%MOD;
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(DP-线性dp-区间dp)