CF 1303E Erase Subsequences
题意:
给一个 \(S\) 串和一个 \(T\) 串,问是否能由 \(S\) 在两次以内生成 \(T\) 串
\(S1\) 一次生成 \(S2\) 是指:从 \(S1\) 取出一个子序列 \(S2\) 并删除,不改变原顺序。
\(S1\) 两次生成 \(S2\) 是指:在 \(S1\) 一次生成 \(T1\) 之后,用剩下的 \(S1\) 生成 \(T2\), \(S2=T1+T1\)
其中 \(len(S), len(T) \le 400\)
题解:
由数据范围可知复杂度为 \(O(N^3)\),而此题与上一场 div3 的 E1 (CF1296E1) 题其实有近似之处,相当于用两次自定义的权值顺序去构造出新串。其实就是最长公共子序列的做法改编。可知 LCS 的复杂度为 \(O(N^2)\),外层套一维枚举 \(T1\) 和 \(T2\) 的分割点复杂度为 \(O(N)\)。
剩下的部分就很显然了,构造 \(dp_{i,j}\) 表示 \(S\) 枚举到 \(i\),\(T1\) 枚举到 \(j\) 时\(T2\) 能取的最大值。
-
第一种转移是不需要条件的 \(dp_{i,j} = dp_{i-1,j}\) 表示多了一层 \(S\) 但是没有作出任何贡献
-
第二种转移是第二维增加 \(dp_{i,j} = dp_{i-1,j-1}\) 表示 \(S_i\) 与 \(T1_j\) 匹配上了
-
第三种转移是第一维增加 \(dp_{i,j} = dp_{i-1,j + 1}\) 表示 \(S_i\) 与 \(T2_{dp[i - 1][j]}\) 匹配上了
代码:
#include <bits/stdc++.h>
#define ll long long
#define X first
#define Y second
#define sz size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<long long> vl;
template <class T>
inline bool scan(T &ret){
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
const ll mod = 1e9+7;
const int maxn = 405+50;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
ll qp(ll x, ll n) {
ll res = 1; x %= mod;
while (n > 0) {
if (n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
// dp[i][j] s(1~i), t1(1~j), t2 val
char s[maxn], t[maxn];
int slen, tlen;
int main(int argc, char* argv[]) {
int T;
scanf("%d", &T);
for (int kase = 1; kase <= T; ++kase) {
scanf("%s%s", s + 1, t + 1);
slen = strlen(s + 1);
tlen = strlen(t + 1);
int flag = 0;
for (int pos = 1; pos <= tlen; ++pos) {
vector<vector<int> > dp(slen + 1);
for (int i = 0; i <= slen; ++i) {
dp[i].resize(pos + 1);
for (int j = 0; j <= pos; ++j) {
dp[i][j] = -1;
}
}
dp[0][0] = 0;
for (int i = 1; i <= slen; ++i) {
for (int j = 0; j <= min(i, pos); ++j) {
dp[i][j] = dp[i - 1][j];
if (dp[i - 1][j] != -1 && dp[i - 1][j] < tlen - pos && s[i] == t[dp[i - 1][j] + pos + 1]) {
dp[i][j] = max(dp[i][j], dp[i - 1][j] + 1);
}
if (j && s[i] == t[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1]);
}
}
// if (pos == 2) {
// for (int i = 0; i <= slen; ++i) {
// for (int j = 0; j <= pos; ++j) {
// printf("%d ", dp[i][j]);
// }
// printf("\n");
// }
// }
if (dp[slen][pos] == tlen - pos) {
flag = 1;
break;
// cerr << pos << endl;
} else if (dp[slen][pos] == -1) break;
}
printf("%s\n", flag ? "YES" : "NO");
}
return 0;
}