T1 Article
给 $m$ 个好串,定义一个字符串分割方案是好的当且仅当它分割出来的子串中"是好串的子串"的串长占原串串长超过 85%,定义一个好的分割方案的权值为这种分割方案中每个"是好串的子串"的子串的最短长度,给 $n$ 个询问串,对每个询问串求最大权值
$n,m \leq 10^5, \sum |S|,\sum |T| \leq 10^6$
sol:
二分最短长度 $L$,做一个 dp
$f_i$ 表示前 $i$ 位字符串最多的"是好串的子串"的长度和是多少,转移就是 $f_i = max\{f_j + (i - j)\} (S[j+1,i] 是好串的子串,i-j \geq L)$
由于 $S[j+1,i]$ 的右端单调递增,可以用后缀自动机来预处理每一个 $S[1,i]$ 最大匹配长度,最大匹配长度显然是单调的,所以可以用单调队列维护 $i+f_i$
然后还要注意一点是这题 85% 以上就行,所以还要加一个 $f_i = f_{i-1}$ 的转移,最后判一下 $f_{len}$ 是否超过原串的 85%
#include <bits/stdc++.h> #define LL long long #define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i) #define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i) using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -f; for(; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0'; return x * f; } const int maxn = 2000010; int m, n; char s[maxn]; int f[maxn]; int root, last, dfn; int tr[maxn][3], fa[maxn], mxlen[maxn], Q[maxn]; inline void extend(int c) { int p = last, np = last = ++dfn; mxlen[np] = mxlen[p] + 1; for(; p && !tr[p][c]; p = fa[p]) tr[p][c] = np; if(!p) fa[np] = root; else { int q = tr[p][c]; if(mxlen[q] == mxlen[p] + 1) fa[np] = q; else { int nq = ++dfn; mxlen[nq] = mxlen[p] + 1; fa[nq] = fa[q]; fa[q] = fa[np] = nq; memcpy(tr[nq], tr[q], sizeof(tr[q])); for(; p && tr[p][c] == q; p = fa[p]) tr[p][c] = nq; } } } int chk(int mid) { int len = strlen(s + 1); int p = root, cl = 0, HD = 1, TL = 0; rep(i, 1, len) { int c = s[i] - 'a'; if(tr[p][c]) p = tr[p][c], cl++; else { for(; p && !tr[p][c]; p = fa[p]); if(!p) cl = 0, p = root; else cl = mxlen[p] + 1, p = tr[p][c]; } f[i] = f[i - 1]; int lf = i - cl, rig = i - mid; if(rig < 0) continue; while(HD <= TL && f[Q[TL]] - Q[TL] < f[rig] - rig) --TL; Q[++TL] = rig; while(HD <= TL && Q[HD] < lf) ++HD; if(HD <= TL)f[i] = max(f[i], i + f[Q[HD]] - Q[HD]); } return (f[len] * 20) >= (len * 17); } int main() { // freopen("article.in","r",stdin); // freopen("article.out","w",stdout); root = last = ++dfn; n = read(), m = read(); rep(i, 1, m) { scanf("%s", s + 1); int len = strlen(s + 1); last = 1; rep(i, 1, len) extend(s[i] - 'a'); } rep(i, 1, n) { scanf("%s", s + 1); int l = 0, r = strlen(s + 1), ans = -1; while(l <= r) { int mid = (l + r) >> 1; if(chk(mid)) l = mid + 1, ans = mid; else r = mid - 1; } cout << ans << '\n'; } } /* 1 2 babba aaaaabbba babbaabbaa */