CF346B kmp+dp

這道題應該是比較典型的利用kmp去dp的題目。
我們思考題意他要求我們的子序列不能夠和virus串完全匹配,那麼我們就可以在原先求最長公共子序列的基礎上在加一個維度。就是
f[i][j][z],第一個串枚舉到i,第二個串枚舉到j,然後他們與virus串匹配的長度是z。
接下來思考轉移。
第一個串當做A數組,第二個串當做B數組
即當(A[i] == B[j])的時候可以在原先已經有的子序列基礎上加上字符A[i],這個時候與virus匹配到的長度是z。那麼這個長度z是由誰轉移來的?
這個地方需要kmp去預處理。我們枚舉virus串的長度,然後就假設當前長度爲templen,然後枚舉下一個字符是誰‘A’-‘Z’,利用next數組就可以得到加上下一個字符後,與virus串匹配上的長度,(這個部分就是kmp的最基礎應用)
預處理後我們就可以知道有哪些狀態加上A【i】這個字符可以到達z狀態,這就可以進行轉移了。

唯一與最長公共子序列有區別就是(A[i] == B[j]),其他是一樣的。
複雜度就是O( | s1 | * | s2 | * | virus|)
在輸出路徑方面就是和大部分輸出路徑一樣倒推回去就好了

char A[max_], B[max_], S[max_];
int next_[max_],lenS,lenA,lenB;
il void getnext() {
	lenS = strlen(S + 1);
	int j = 0;
	for (int i = 2; i <= lenS; i++) {
		while (j&&S[j + 1] != S[i]){
			j = next_[j];
		}
		if (S[j + 1] == S[i])j++;
		next_[i] = j;
	}
}
vector<int> to[max_][30];
int f[max_][max_][max_];
void dfs(int i, int j, int z) {
	if (A[i] == B[j]) {
		for (auto qian : to[z][A[i] - 'A']) {
			if (f[i][j][z] == f[i - 1][j - 1][qian] + 1) {
				dfs(i - 1, j - 1, qian);
				cout << A[i];
				return;
			}
		}
	}
	if (f[i][j][z] == f[i - 1][j][z]) {
		dfs(i - 1, j, z); return;
	}
	if (f[i][j][z] == f[i][j - 1][z]) {
		dfs(i, j - 1, z); return;
	}
}
signed main() {	
	cin >> (A + 1) >> (B + 1) >> (S + 1);
	lenA = strlen(A + 1);
	lenB = strlen(B + 1);
	getnext();
	for (int i = 0; i <= lenS; i++) {
		for (int j = 0; j <= 25; j++) {
			int now = i;
			while (now && S[now + 1]!='A'+j){
				now = next_[now];
			}
			if (S[now + 1] == 'A' + j)now++;
			to[now][j].push_back(i);
		}
	}
	for (int i = 1; i <= lenA; i++) {
		for (int j = 1; j <= lenB; j++) {
			for (int z = 0; z < lenS; z++) {
				if (A[i] == B[j]) {
					for (auto qian : to[z][A[i] - 'A']) {
						f[i][j][z] = max(f[i][j][z], f[i - 1][j - 1][qian] + 1);
					}
				}
				f[i][j][z] = max(f[i][j][z], f[i - 1][j][z]);
				f[i][j][z] = max(f[i][j][z], f[i][j - 1][z]);
			}
		}
	}
	int ans = 0,stu;
	for (int i = 0; i < lenS; i++) {
		if (ans < f[lenA][lenB][i]) {
			ans = f[lenA][lenB][i];
			stu = i;
		}
	}
	if (ans == 0) { cout << 0; return 0; }
	dfs(lenA, lenB, stu);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章