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; }