Address
https://www.lydsy.com/JudgeOnline/problem.php?id=3214
Solution
为甚么做此题的人比 K 大数查询少……
首先把每个单词求下 hash ,只需要用 int 即可,不需要取膜。
然后在
T
T
中,从左往右贪心匹配,匹配出 的一个等于
A
A
的子序列,使子序列的右端点最靠左。设这个右端点为 。
同样地,也可以贪心匹配出
T
T
的一个等于 的子序列,使左端点尽量靠右,为
R
R
。
继续在 内匹配子序列
B
B
,使 的最左端点
l
l
和 最右端点 满足
r−l
r
−
l
最小。
考虑到同一单词出现的次数
≤500
≤
500
,可以枚举
B
B
的左端点 后再贪心匹配出最小的
r
r
。
这样,复杂度就是 。
cnt
c
n
t
为
B
B
第一个字符在 的
(L,R)
(
L
,
R
)
内的出现次数。
Code
注:单词的分隔符不一定是空格,也可能是小写字母以外的其他字符。被这个坑了好久
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
const int N = 3e5 + 5, INF = 0x3f3f3f3f;
int L, R, nt, na, nb, nc, t[N], a[N], b[N], c[N], ans;
char T[N], A[N], B[N], C[N];
void __hash(char *s, int *rp, int &n, int len) {
int i;
For (i, 0, len - 1)
if (s[i] < 'a' || s[i] > 'z') continue;
else {
if (i == 0 || s[i - 1] < 'a' || s[i - 1] > 'z') rp[++n] = 0;
rp[n] = rp[n] * 27 + s[i] - 'a' + 1;
}
}
int main() {
int i, j, th = 1;
gets(T); gets(A); gets(B); gets(C);
__hash(T, t, nt, strlen(T));
__hash(A, a, na, strlen(A));
__hash(B, b, nb, strlen(B));
__hash(C, c, nc, strlen(C));
For (L, 1, nt)
if (t[L] == a[th]) {
if (th == na) {L++; break;}
else th++;
}
else ans++;
th = nc;
Rof (R, nt, 1)
if (t[R] == c[th]) {
if (th == 1) {R--; break;}
else th--;
}
else ans++;
int minp = INF;
For (i, L, R) {
if (t[i] != b[1]) continue;
th = 0; int mp = 0;
For (j, i, R)
if (t[j] == b[th + 1]) {
th++;
if (th == nb) break;
}
else mp++;
if (th == nb) minp = min(minp, mp);
}
cout << ans + minp << endl;
return 0;
}