題意分析:
凱撒有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;
}