poj3046(递推)

链接:点击打开链接

题意:有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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值