[CodeForces 118D]Caesar's Legions[DP]

題目鏈接:[CodeForces 118D]Caesar's Legions[DP]

題意分析:

凱撒有n1個步兵和n2個騎兵,現在將他們排成一列,問總共有多少種不同的排列情況?(步兵不能連着超過k1個,騎兵不能連着超過k2個)

解題思路:

首先倒着考慮狀態看看行不行,比如已經放置了n1個步兵和n2個騎兵的方法總數,那麼這個狀態的上一個狀態應該考慮到當前狀態中,最後一個兵種是什麼,然後考慮來的狀態有多少個,發現這樣考慮蠻複雜的。那麼試試正着考慮:正着考慮,先想到從第i個位置出發,有多少種方法,發現這樣的話,有三個東西不知道:當前的排頭兵是什麼兵種,這個兵種連續了幾個,用了多少個這種兵種。那麼悉數補上,就有dp[i][j][s][k]表示從第i個位置開始,步兵使用了j個,當前兵種爲s(0:步兵,1:騎兵),連續了k個,然後就能轉移了。

個人感受:

第二次做了。昨天還沒思路= =,今天發現可以正着推,23333

具體代碼如下:

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define lowbit(x) (x & (-x))
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1  1
#define ll long long
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;

const int MOD = 1e8;

int n1, n2, k1, k2;
int dp[300][111][2][20];

int dfs(int n, int num, int sta, int len) {
    //cout << n << '-' << num << '-' << sta << '-' << len << '\n';
    int &x = dp[n][num][sta][len];
    if (x != -1) return x;
    x = 0;
    if (n > n1 + n2) return 0;
    if (n == n1 + n2 && num == n1) return x = 1;

    if (sta == 0) {
        if (num + 1 <= n1 && len + 1 <= k1)
            x += dfs(n + 1, num + 1, 0, len + 1);
        if (n + 1 - num <= n2)
            x += dfs(n + 1, num, 1, 1);
    }
    else {
        if (num + 1 <= n1)
            x += dfs(n + 1, num + 1, 0, 1);
        if (len + 1 <= k2 && n + 1 - num <= n2)
            x += dfs(n + 1, num, 1, len + 1);
    }
    return x % MOD;
}

int main()
{
    cin >> n1 >> n2 >> k1 >> k2;
    memset(dp, -1, sizeof dp);
    cout << dfs(0, 0, 0, 0) << '\n';
    return 0;
}


發佈了231 篇原創文章 · 獲贊 18 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章