Ant Counting POJ - 3046【dp-多重集组合数-模板】
题意简述:有t种蚂蚁 ,a个蚂蚁 每个蚂蚁属于一个种类 不同类蚂蚁可以区分 同类蚂蚁不可以区分 求这些蚂蚁组成大小为s s+1…b集合的组合数
多重集组合数模板
n种物品,第i种物品有ai个,不同种类物品可以互相区分但是相同种类无法区分。从这些物品中取出m个,求方案数。
——方法来源于《挑战程序设计竞赛》P68-69
注意这里的物品种类编号是从0~n-1的
Code View
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
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<n;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<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
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;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com