1. 程式人生 > >POJ 3046 Ant Counting——多重集組合數

POJ 3046 Ant Counting——多重集組合數

定義dp【i】【j】為從前i種物品中選j個物品對應的方案總數

狀態轉移方程為:dp【i】【j】 = ∑dp【i-1】【j-k】(k的範圍是【0,min(j,cnt【i】)】)

優化的話只要寫出dp【i】【j】和dp【i】【j-1】對應的求和展開式就能找到兩者之間的關係,從而去掉一重迴圈

最後用滾動陣列優化一下空間,雖然這題不優化也能過

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 1e6;
int T, A, S, B, a[1005];
int dp[2][100005];

void solve() {
    dp[0][0] = dp[1][0] = 1;
    for (int i = 1; i <= T; i++) {
        for (int j = 1; j <= B; j++) {
            if (j - 1 >= a[i]) dp[i&1][j] = (dp[i&1][j-1]+dp[(i-1)&1][j]-dp[(i-1)&1][j-1-a[i]]+mod)%mod;
            else dp[i&1][j] = (dp[i&1][j-1]+dp[(i-1)&1][j])%mod;
        }
    }
}

int main() {
    while (~scanf("%d %d %d %d", &T, &A, &S, &B)) {
        memset(a, 0, sizeof(a));
        int x;
        for (int i = 1; i <= A; i++) {
            scanf("%d", &x);
            a[x]++;
        }
        solve();
        int ans = 0;
        for (int i = S; i <= B; i++) ans = (ans + dp[T&1][i])%mod;
        printf("%d\n", ans);
    }
    return 0;
}