http://poj.org/problem?id=3046
就是这种模型:
给 N 种物品,每种有 ai 个,从中选出 m 个,求方案数?
参考博客:https://blog.csdn.net/ac_hell/article/details/51405598
还是直接来样例比较直接:
样例就是:有 两个 1,两个 2 ,一个 3,问从中选 2 个数 加上 从中选 3 个数的方案数之和
dp[i][j] 表示从前 i 种物品中,选出 j 个的方案数
那就是求 dp[3][2]+dp[3][3]
求 dp[3][2]:
就是当前在处理第三种物品
假如这次第三种物品一个都不拿,那么方案数就是 dp[2][3−0]
假如这次第三种物品拿 1 个,那么方案数就是 dp[2][3−1]
假如这次第三种物品拿 2 个,那么方案数就是 dp[2][3−2]
依次类推。。。。
所以方程就出来了:
dp[i][j]=dp[i−1][j−0]+ d[i−1][j−1]+dp[i−1][j−2]+.....+dp[i−1][j−j]
但是这道题的妙点在于优化(虽然好像不优化也能过)
优化
而后面这一坨红色的是不是相当于 从拿 1 个,拿 2 个。。。。直到拿完,
而我们的 dp 是从拿 0 个开始,直到拿完,是不是感觉只有一点点的差别
那我们的 j 比原来少拿一个,变成 j−1,不是就相当于从 0 个开始拿了么~~~
所以后面这一坨红色的其实是 dp[i][j−1]
<mark>那么方程就变成了: dp[i][j]=dp[i−1][j−0]+ dp[i][j−1]</mark>
这个方程就是主要的思路,然后就是一些细节问题了,比如我们这里的 dp[3][2],第 3 个物品最多才 1 个,怎么能拿 2 个哇,
所以当当前这一种个数不够的时候就要减去那么多,就变成:
<mark> dp[i][j]=dp[i−1][j−0]+ dp[i][j−1]−dp[i−1][j−1−c]</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;
}
}