【題解】 zoj 3747 計數dp 進擊的巨人

其實只是因爲要給同學出題找的這道題, 不過在網上看到的一些題解似乎對一個細節並沒有寫得清楚,在此寫個題解
沒想到之前太早發,又碰上愛學習的神犇wx同學…


題目

題意

有GRP三個軍種,G最多連續M個,R最少連續K個,求安排N個的方案數

輸入

有多個測試用例(反正跑得過)。對於每種情況,存在包含3個整數N(0

輸出

每種情況下一行,應輸出mod 1000000007後的結果

輸入樣例

3 2 2

輸出樣例

5

說明

將駐軍,偵察機關和軍警視爲G,R和P.
合理安排有:GGG,GGR,GGP,RGG,PGG。


題解

因要判斷不同軍種連續性問題,需要開兩維,一維表示當前是第i個,一維表示當前軍種爲j

達成共識

首先爲了方便用同一個表示方法表示,當然最好是將最多最少連續同一:將最多連續轉化爲最少連續或將最少連續轉化爲最多連續
上面設的部分中還沒說表示什麼,比較可以發現將最少連續轉化爲最多連續是最方便的
而如何將最少連續轉化爲最多連續呢?
類似組合數學的,可以用最多連續N個減去最多連續M-1個表示
用u,v表示每次計算時G最多連續u個,R最多連續v個
答案即爲兩次遞推答案相減,v不變,u一次爲N,一次爲M-1

分三個軍種討論

j表示P時

無需考慮前面情況,全部加起來即可

j表示G時

i <=u時

不可能多過連續要求,全部加起來即可

i == u+1時

有一種情況正好超過連續要求,全部加起來減去1即可

i>u+1時

我就是說這個細節應該用更好的方式理解
當然會有多種情況超過連續要求
這個時候網上的題解是類似於

//減去i-1~i-u-1全是G的情況

其實我覺得可以跟之前最少連續轉最多連續一樣的方法理解
爲了不出現超過連續要求的情況,
逆向思考這種情況即爲 至少有i-u個其他兵種在前,於是
每一個其他兵種這樣的情況自然爲(fi1,xfiu1,x) ,有兩種其他兵種,與當前兵種正常加起來即可

j表示R時

類似可推出


代碼

#include <cstdio>
#include <cstring>

const int mod = 1000000007, maxn = 1e6 + 100;
typedef long long ll;
ll dp[maxn][3]; //0 G, 1 R, 2 P
int n, m, k;
ll work(int u, int v){
    dp[0][0] = dp[0][1] = 0, dp[0][2] = 1;
    ll res;
    for (int i = 1, j = 0; i <= n; ++i, ++j){
    dp[i][0] = dp[i][1] = dp[i][2] = res
        = ((dp[j][0] + dp[j][1]) % mod + dp[j][2]) % mod;
    if (i == u + 1) dp[i][0] = res - 1;
    if (i > u + 1) dp[i][0] = res - dp[j - u][1] - dp[j - u][2];
    if (i == v + 1) dp[i][1] = res - 1;
    if (i > v + 1) dp[i][1] = res - dp[j - v][0] - dp[j - v][2];
    }
    return ((dp[n][0] + dp[n][1]) % mod + dp[n][2]) % mod;
}
int main (){
    //freopen ("titans.in", "r", stdin);
    //freopen ("titans.out", "w", stdout);
    ll ans;
    while(~scanf ("%d%d%d", &n, &m, &k)){
    printf ("%lld\n", ((work(n, k) - work(m - 1, k)) % mod + mod) % mod);
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章