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
*/
View Code

相关文章: