POJ3046选蚂蚁创建集合_线性DP
一个人的精力是有限的呢,如果一直做一件事迟早会疲惫,所以自己要把握好,不要一直埋头于一件事,否则效率低下还浪费时间
题目大意:一共有T(1,2.。。n为其种类)种蚂蚁,A个蚂蚁,问你从这T种蚂蚁中选取[S,B]个,可以构成多少个集合
dp[i][j]表示前i种蚂蚁我选j个可以构成集合的种数,与其说是dp不如说是递推
那么对于当前这个i我们是不是有两种决策1.一个都不选所得到的决策值是dp[i-1][j]2.至少选一个那么决策值就是dp[i][j-1]
后续的先不管,让他递推过去就有啦,但是递推递推我们发现dp[i][j-1]不仅仅表示第i种至少选一个的决策值,还表示前i种选j-1
个的决策值,是不是包含了选ant[i]个第[i]种的情况,但是目前已经选了一个第i种了,这样蚂蚁就超数了,所以这种情况是多余的,但是也得判断一下j有没有那么大啦,嗯这样就庄毅成功题目解决了。
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#define inf (1 << 30)
#define MOD 1000000
using namespace std;
const int maxn = 1e5 + 10;
const int maxm = 1e3 + 10;
/*
T个家族,Ni对应的蚂蚁数目
dp[i][j]表示前i种蚂蚁中选j个可以组成的总数
第i种选择k个,k<= ant[i] && j - K >= 0
dp[i][j] = 求和(dp[i-1][j-k])
复杂度为A2
优化递推公式
第二种不选或至少选择一个
如果不选dp[i][j] = dp[i-1][j]
至少选择一个呢dp[i][j] = dp[i][j-1] - dp[i-1][j-ant[i]-1]
相当于又考虑了前i种选j-1个可以组成的总数,包含了ant[i]个第i种
dp[i][j-1]包含了一部分dp[i-1][j] 所以dp[i-1][j - ant[i]- 1]
所以dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-ant[i]-1]
复杂度为O(TB)
*/
int ant[1005];
int dp[2][maxn];
int ans;
int main()
{
int T,A,S,B;
scanf("%d%d%d%d",&T,&A,&S,&B);
for(int i = 1;i <= A;i++)
{
int op;
scanf("%d",&op);
ant[op]++;
}
dp[0][0] = dp[1][0] = 1;
for(int i = 1;i <= T;i++)
{
for(int j = 1;j <= B;j++)
{
//有重叠的部分
if(j - ant[i] - 1 >= 0)dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1] - dp[(i - 1) % 2][j - ant[i] - 1] + MOD) % MOD; //在取模时若出现了减法运算则需要先+Mod再对Mod取模,防止出现负数(如5%4-3%4为负数)
else dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1]) % MOD;
}
}
for (int i = S; i <= B; i++)
ans = (ans + dp[T % 2][i]) % MOD;
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号