链接:点击打开链接
题意:有A个数,一共T种,从中选一些数作为一个集合,问集合大小在A到B中的种类有多少
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stdlib.h>
using namespace std;
const long long MOD=1000000;
long long dp[1005][100005];
long long num[1005];
int main(){
long long T,A,S,B,i,j,x,ans;
while(scanf("%I64d%I64d%I64d%I64d",&T,&A,&S,&B)!=EOF){
memset(num,0,sizeof(num));
for(i=0;i<A;i++){
scanf("%I64d",&x);
num[x-1]++;
} //定义dp[i][j]是从前i种物品中取出j个的组合总数
for(i=0;i<=T;i++) //所以可以从前i-1中物品中取出j-k个,再从第i种物
dp[i][0]=1; //品种取出k个,可以推出递推关系式
for(i=0;i<T;i++) //dp[i+1][j]=∑{k=0~min(j,a[i])}dp[i][j-k]可以展开
for(j=1;j<=B;j++){ //因此可以看出∑{k=0~min(j-1,a[i])}dp[i][j-1-k]相比
if(j-1-num[i]>=0) //∑{k=0~min(j,a[i])}dp[i][j-k]差了一个dp[i][j]和
dp[i+1][j]=(dp[i+1][j-1]+dp[i][j]-dp[i][j-1-num[i]]+MOD)%MOD;
else //dp[i][j-1-ai],又因为dp[i+1][j]=∑{k=0~min(j,a[i])}
dp[i+1][j]=(dp[i+1][j-1]+dp[i][j])%MOD; //dp[i][j-k],所以∑{k=0~min(j-1,a[i])}dp[i][j-1-k]=
} //dp[i+1][j-1].所以可以推出优化后的递推式
ans=0; //dp[i+1][j]=dp[i+1][j-1]+dp[i][j]-dp[i][j-1-ai]
for(j=S;j<=B;j++)
ans=(ans+dp[T][j])%MOD; //从S到B加和并取余
printf("%I64d\n",ans);
}
return 0;
}