[JOI 2013 Final]搭乘 IOI 火車

maniubi發表於2024-10-10

[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;
}

相關文章