POJ3046选蚂蚁创建集合_线性DP

POJ3046选蚂蚁创建集合

一个人的精力是有限的呢,如果一直做一件事迟早会疲惫,所以自己要把握好,不要一直埋头于一件事,否则效率低下还浪费时间

题目大意:一共有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;
}

猜你喜欢

转载自www.cnblogs.com/DF-yimeng/p/9375478.html