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][3−0]
假如这次第三种物品拿
1
1
1 个,那么方案数就是
d
p
[
2
]
[
3
−
1
]
dp[2][3-1]
dp[2][3−1]
假如这次第三种物品拿
2
2
2 个,那么方案数就是
d
p
[
2
]
[
3
−
2
]
dp[2][3-2]
dp[2][3−2]
依次类推。。。。
所以方程就出来了:
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 0 ] + dp[i][j]=dp[i-1][j-0]+ dp[i][j]=dp[i−1][j−0]+ 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[i−1][j−1]+dp[i−1][j−2]+.....+dp[i−1][j−j]
但是这道题的妙点在于优化(虽然好像不优化也能过)
优化
而后面这一坨红色的是不是相当于 从拿
1
1
1 个,拿
2
2
2 个。。。。直到拿完,
而我们的
d
p
dp
dp 是从拿
0
0
0 个开始,直到拿完,是不是感觉只有一点点的差别
那我们的
j
j
j 比原来少拿一个,变成
j
−
1
j-1
j−1,不是就相当于从
0
0
0 个开始拿了么~~~
所以后面这一坨红色的其实是
d
p
[
i
]
[
j
−
1
]
dp[i][j-1]
dp[i][j−1]
那么方程就变成了: d p [ i ] [ j ] = d p [ i − 1 ] [ j − 0 ] + dp[i][j]=dp[i-1][j-0]+ dp[i][j]=dp[i−1][j−0]+ d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1]
这个方程就是主要的思路,然后就是一些细节问题了,比如我们这里的
d
p
[
3
]
[
2
]
dp[3][2]
dp[3][2],第
3
3
3 个物品最多才
1
1
1 个,怎么能拿
2
2
2 个哇,
所以当当前这一种个数不够的时候就要减去那么多,就变成:
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
0
]
+
dp[i][j]=dp[i-1][j-0]+
dp[i][j]=dp[i−1][j−0]+
d
p
[
i
]
[
j
−
1
]
−
d
p
[
i
−
1
]
[
j
−
1
−
c
]
dp[i][j-1]-dp[i-1][j-1-c]
dp[i][j−1]−dp[i−1][j−1−c]
诶不对啊,后面多的不一定只有 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;
}
}