個人博客鏈接:https://blog.nuoyanli.com/2020/03/25/cf1203d2/
鏈接
https://codeforces.com/problemset/problem/1203/D2
題意
有一個字符串,以及中的一個子序列,現在要求你將刪去最長一段字串,刪去之後還是的子序列,求刪去的最長字串有多長。
思路
只三種情況,刪去的是的前綴、後綴、中間一段。處理也很容易,儘量在前面找出來,儘量在後面找出來,並且記錄找出的中每一個字符對應在中的位置,這個時候刪去前綴後綴就直接解決了問題。中間一段就枚舉從前面找個字符,後面找個字符,因爲之前已經處理了相對的位置,減一下,中間就出來了。
詳細見代碼
參考代碼
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
#define PB push_back
#define FI first
#define SE second
#define m_p(a, b) make_pair(a, b)
const double pi = acos(-1.0);
const double eps = 1e-9;
typedef long long LL;
const int N = 1e6 + 10;
const int M = 1e5 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double f = 2.32349;
char s[N], t[N];
int lens, lent, pre[N], suf[N];
// lens爲s的長度,lent爲t的長度,pre記錄t在s儘量前端找出來的時候相對每個字母位置,suf爲後段
int pre_m() { //儘量在s前段找出t來
int ls = 0, lt = 0, cnt = 0;
for (int i = 0; i < lens; i++) {
if (s[ls] == t[lt]) {
lt++;
pre[++cnt] = ls;
}
ls++;
if (lt == lent)
break;
}
return lens - ls;
}
int tail_m() { //儘量在s後段找出t來
int rs = lens - 1, rt = lent - 1, cnt = 0;
for (int i = lens - 1; i >= 0; i--) {
if (s[rs] == t[rt]) {
suf[++cnt] = rs;
rt--;
}
rs--;
if (rt == -1)
break;
}
return rs + 1;
}
void solve() {
IOS;
cin >> s >> t;
lens = strlen(s);
lent = strlen(t);
int ans = 0;
ans = max(ans, pre_m());
ans = max(ans, tail_m());
for (int i = 1; i <= lent; i++) {
//刪去中間一段,就用前面和後面找出來的位置拼起來
ans = max(ans, suf[lent - i] - pre[i] - 1);
}
cout << ans << endl;
}
signed main() {
solve();
return 0;
}