Description
描述
给定两个字符串 $s$ 和 $t$。问能否找到 $s$ 的两个不相交的子序列(可以为空) $s_1,s_2$ 使 $t=s_1s_2$。
输入
第一行为一个正整数 $T$($1 le T le 100$)表示数据组数。
接下来每组数据为两个字符串 $s$ 和 $t$($1le|t|le|s|le 400$)。
输出
对于每组数据,一个 YES 或 NO 表示是否可行。
样例
输入
4
ababcd
abcba
a
b
defi
fed
xyz
x输出
YES
NO
NO
YES
Solution
本题解字符串下标从 $1$ 开始。
看到 $1 le |t| le |s| le 400$,盲猜可能是的三次方的做法。
根据题意,第一次操作一定是创造了 $t$ 的前半部分,第二次操作一定是创造了 $t$ 的后半部分。于是我们枚举一下这个断点。用 $t_1$ 来表示 $t_{1cdots len_l}$(前一半),$t_2$ 表示 $t_{|t| - len_r+1 cdots |t|}$(后一半),其中 $len_l = |t| - len_r$,也就是 $len_l + len_r = |t|$。
用 $a_{i, j}$ 表示 $s_{i cdots |s|}$ 中,第一个 $j$ 的位置。也就是 $forall i le k < a_{i,j}, s_k eq j$,同时 $s_{a_{i,j}} = j$。如果 $forall i le k le |s|, s_i e j$ ,那么有 $a_{i,j} = infty$。
考虑 DP,用 $f_{i, j}$ 表示至少需要 $s_1 sim s_{f_{i,j}}$,才能匹配 $t_{1 1 cdots i}$ 和 $t_{2 1 cdots j}$。转移当然是考虑这次匹配 $t_{1 i}$ 还是匹配 $t_{2 j}$,如果是前者,$f_{i,j} = a_{f_{i - 1, j} + 1, t_{1 i}}$(也就是 $f_{i - 1, j}$ 后面第一个 $t_{1 i}$ 的位置);如果是后者,就有 $f_{i,j} = a_{f_{i, j - 1} + 1, t_{2 j}}$。两者取个 $min$ 即可。最终的成功与否取决于 $f_{len_l, len_r}$ 是否等于 $infty$。如果 $a$ 已经求出来了,这部分将是 $O(|t|^2)$ 的。但是外层还要枚举断点,所以其实是 $O(|t|^3)$。
至于 $a$ 的话,可以从 $|s| o 1$ 更新,首先把 $a_{i}$ 复制为 $a_{i + 1}$,然后把 $a_{i, s_i}$ 更新为 $i$ 即可。这个是 $O(Sigma cdot |s|)$ ($Sigma$ 表示字符集大小)的,常数比较优秀。当然也可以按照定义写一个 $O(Sigma cdot |s|^2)$ 的,不影响时间复杂度。
#include <bits/stdc++.h> using namespace std; const int N = 405; int f[N][N], a[N][30]; const int INF = 0x3f3f3f3f; int main() { ios::sync_with_stdio(false); int t; cin >> t; while(t--) { string s, t; cin >> s >> t; int ls = s.size(), lt = t.size(); s = " " + s; t = " " + t; bool ok = false; for(int lenl = 1; lenl <= lt; lenl++) { string t1 = " " + t.substr(1, lenl); string t2 = " " + t.substr(lenl + 1, lt - lenl); memset(f, 0, sizeof f); f[0][0] = true; memset(a[ls + 1], 0x3f, sizeof a[ls + 1]); for(int i = ls; i; i--) { memcpy(a[i], a[i + 1], sizeof a[i]); a[i][s[i] - 'a'] = i; } int lenr = lt - lenl; memset(f, 0x3f, sizeof f); f[0][0] = 0; for(int i = 0; i <= lenl; i++) { for(int j = 0; j <= lenr; j++) { if(i && f[i - 1][j] != INF) f[i][j] = min(f[i][j], a[f[i - 1][j] + 1][t1[i] - 'a']); if(j && f[i][j - 1] != INF) f[i][j] = min(f[i][j], a[f[i][j - 1] + 1][t2[j] - 'a']); } } if(f[lenl][lenr] != INF) { ok = true; break; } } cout << (ok ? "YES" : "NO") << endl; } return 0; }