题解:P8020 [ONTAK2015] Badania naukowe
forever_nope · · 题解
注意到我们要求答案一定存在
因此,我们考虑枚举
我们使用
同理,使用
于是,我们枚举
那么,如果从
考虑如何表示答案?
设
设
那么,答案可以表示为,
也就是前面的和后面的 LCS 可以直接计入答案,再加上子串
如何求 LCS(最长公共子序列)。
以
表示如果相同,则加入 LCS,否则删去一个继续匹配。
反过来,
同理的。
合起来就行了,核心代码:
constexpr int N = 3e3 + 10;
void init_matching(int n, int *A, int k, int *C, int *P) {
for (int i = 1; i + k - 1 <= n; ++i) {
int p = i, q = 1;
while (p <= n && q <= k) {
q += (A[p] == C[q]);
++p;
}
P[i] = (q > k) ? p - 1 : 0;
}
}
int n, A[N], P[N];
int m, B[N], Q[N];
int k, C[N];
int F[N][N], G[N][N];
void init_LCS() {
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
if (A[i] == B[j])
F[i][j] = F[i - 1][j - 1] + 1;
else
F[i][j] = max(F[i][j - 1], F[i - 1][j]);
}
void init_rLCS() {
for (int i = n; i >= 1; --i)
for (int j = m; j >= 1; --j)
if (A[i] == B[j])
G[i][j] = G[i + 1][j + 1] + 1;
else
G[i][j] = max(G[i][j + 1], G[i + 1][j]);
}
int get_ans() {
int Ans = -1;
for (int i = 1; i + k - 1 <= n; ++i)
for (int j = 1; j + k - 1 <= m; ++j)
if (P[i] && Q[j])
Ans = max(Ans, F[i - 1][j - 1] + G[P[i] + 1][Q[j] + 1] + k);
return Ans;
}
void Main() {
cin >> n;
copy_n(istream_iterator<int>(cin), n, A + 1);
cin >> m;
copy_n(istream_iterator<int>(cin), m, B + 1);
cin >> k;
copy_n(istream_iterator<int>(cin), k, C + 1);
init_matching(n, A, k, C, P);
init_matching(m, B, k, C, Q);
init_LCS(), init_rLCS();
cout << get_ans() << endl;
}