http://poj.org/problem?id=3046
就是这种模型:
N N N 种物品,每种有 a i a_i ai 个,从中选出 m m m 个,求方案数?
参考博客:https://blog.csdn.net/ac_hell/article/details/51405598
还是直接来样例比较直接:
样例就是:有 两个 1 1 1,两个 2 2 2 ,一个 3 3 3,问从中选 2 2 2 个数 加上 从中选 3 3 3 个数的方案数之和
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示从前 i i i 种物品中,选出 j j j 个的方案数
那就是求 d p [ 3 ] [ 2 ] + d p [ 3 ] [ 3 ] dp[3][2]+dp[3][3] dp[3][2]+dp[3][3]

d p [ 3 ] [ 2 ] dp[3][2] dp[3][2]
就是当前在处理第三种物品
假如这次第三种物品一个都不拿,那么方案数就是 d p [ 2 ] [ 3 0 ] dp[2][3-0] dp[2][30]
假如这次第三种物品拿 1 1 1 个,那么方案数就是 d p [ 2 ] [ 3 1 ] dp[2][3-1] dp[2][31]
假如这次第三种物品拿 2 2 2 个,那么方案数就是 d p [ 2 ] [ 3 2 ] dp[2][3-2] dp[2][32]
依次类推。。。。
所以方程就出来了:

d p [ i ] [ j ] = d p [ i 1 ] [ j 0 ] + dp[i][j]=dp[i-1][j-0]+ dp[i][j]=dp[i1][j0]+ d [ i 1 ] [ j 1 ] + d p [ i 1 ] [ j 2 ] + . . . . . + d p [ i 1 ] [ j j ] d[i-1][j-1]+dp[i-1][j-2]+.....+dp[i-1][j-j] d[i1][j1]+dp[i1][j2]+.....+dp[i1][jj]

但是这道题的妙点在于优化(虽然好像不优化也能过)

优化

而后面这一坨红色的是不是相当于 从拿 1 1 1 个,拿 2 2 2 个。。。。直到拿完,
而我们的 d p dp dp 是从拿 0 0 0 个开始,直到拿完,是不是感觉只有一点点的差别

那我们的 j j j 比原来少拿一个,变成 j 1 j-1 j1,不是就相当于从 0 0 0 个开始拿了么~~~
所以后面这一坨红色的其实是 d p [ i ] [ j 1 ] dp[i][j-1] dp[i][j1]

<mark>那么方程就变成了: d p [ i ] [ j ] = d p [ i 1 ] [ j 0 ] + dp[i][j]=dp[i-1][j-0]+ dp[i][j]=dp[i1][j0]+ d p [ i ] [ j 1 ] dp[i][j-1] dp[i][j1]</mark>

这个方程就是主要的思路,然后就是一些细节问题了,比如我们这里的 d p [ 3 ] [ 2 ] dp[3][2] dp[3][2],第 3 3 3 个物品最多才 1 1 1 个,怎么能拿 2 2 2 个哇,
所以当当前这一种个数不够的时候就要减去那么多,就变成:
<mark> d p [ i ] [ j ] = d p [ i 1 ] [ j 0 ] + dp[i][j]=dp[i-1][j-0]+ dp[i][j]=dp[i1][j0]+ d p [ i ] [ j 1 ] d p [ i 1 ] [ j 1 c ] dp[i][j-1]-dp[i-1][j-1-c] dp[i][j1]dp[i1][j1c]</mark>

诶不对啊,后面多的不一定只有 j-1-c 这一个啊,万一还多了 j-2-c,j-3-c,这些怎么办喃?为啥就只减去这一项?还是有点没想通

#include"iostream"
#include"string.h"
using namespace std;
const int MOD=1e6;
const int maxn=1e3+5;
int dp[2][maxn*maxn];
int a[maxn];
int main()
{
    int N,ge,qL,qR;
    while(cin>>N>>ge>>qL>>qR)
    {
        memset(a,0,sizeof(a));
        for(int i=1;i<=ge;i++)
        {
            int t;
            cin>>t;
            a[t]++;
        }
        int pre=0,now=0;
        memset(dp,0,sizeof(dp));
        dp[0][0]=dp[1][0]=1;
        int M=0;
        for(int i=1;i<=N;i++)
        {
            now=pre^1;
            M+=a[i];
            for(int j=1;j<=M;j++)
            {
                if(j<=a[i])dp[now][j]=dp[pre][j]+dp[now][j-1];
                else dp[now][j]=dp[pre][j]+dp[now][j-1]-dp[pre][j-1-a[i]];
                dp[now][j]=(dp[now][j]%MOD+MOD)%MOD;
            }
            pre=now;
        }
        long long ans=0;
        for(int i=qL;i<=qR;i++)
        {
            ans+=dp[now][i];
            if(ans>MOD)ans%=MOD;
        }
        cout<<ans<<endl;
    }
}