[JOI 2013 Final]搭乘 IOI 火車
題意
給出兩個由 \(\text{OI}\) 組成的字串 \(S,T\)。
可以刪除每個字串的字首和字尾。
每次從剩下部分的第一位取出一個字元放到新的字串中。
要求新字串必須以 \(\text{I}\) 開頭結尾,相同的字元不能相鄰,求新字串的最大長度。
思路
定義 \(dp_{i,j,0/1,0/1}\) 表示考慮到 \(S\) 的第 \(i\) 位,\(T\) 的第 \(j\) 位,
已經沒刪完/刪完了字首,上一位填的是 \(\text{B}\)/\(\text{I}\)。
轉移可用記憶化搜尋的方式實現,好寫好調。
注意陣列開夠以及初始化(如果當前為 \(\text{I}\) 則初始化為 \(0\),否則為 \(-\infin\))。
程式碼
#include <bits/stdc++.h>
using namespace std;
const int N = 2005; // 陣列要開到MAXN+1, 下面要訪問
int n, m;
char S[N], T[N];
int dp[N][N][2][2];
int dfs(int Sx, int Tx, int b, int state) {
if (Sx == n + 1 && Tx == m + 1) return (state == 1 ? 0 : -1e9);
int &res = dp[Sx][Tx][b][state];
if (res != -1) return res;
res = (state == 1 ? 0 : -1e9); // 初始化
if (!b) {
if (Sx <= n) res = max(res, dfs(Sx + 1, Tx, 0, state));
if (Tx <= m) res = max(res, dfs(Sx, Tx + 1, 0, state));
}
if (Sx <= n && state == 0 && S[Sx] == 'I')
res = max(res, dfs(Sx + 1, Tx, 1, 1) + 1);
if (Sx <= n && state == 1 && S[Sx] == 'O')
res = max(res, dfs(Sx + 1, Tx, 1, 0) + 1);
if (Tx <= m && state == 0 && T[Tx] == 'I')
res = max(res, dfs(Sx, Tx + 1, 1, 1) + 1);
if (Tx <= m && state == 1 && T[Tx] == 'O')
res = max(res, dfs(Sx, Tx + 1, 1, 0) + 1);
return res;
}
int main() {
freopen("train.in", "r", stdin);
freopen("train.out", "w", stdout);
memset(dp, -1, sizeof(dp));
cin >> n >> m;
scanf("%s%s", S + 1, T + 1);
cout << max(0, dfs(1, 1, 0, 0))<< "\n";
return 0;
}