luogu P6640 [BJOI2020] 封印

https://www.luogu.com.cn/problem/P6640

北京省选就这?
首先肯定是把T建一颗SAM,
然后考虑按照套路把S丢进去跑,得到 s l [ i ] sl[i] sl[i]表示最大的长度满足 S [ i − s l [ i ] + 1 , i ] S[i-sl[i]+1,i] S[isl[i]+1,i] T T T的子串

对于一个询问 [ l , r ] [l,r] [l,r],可以发现答案就是
max ⁡ i = l r ( min ⁡ ( s l [ i ] , i − l + 1 ) ) \max\limits_{i=l}^r (\min(sl[i],i-l+1)) i=lmaxr(min(sl[i],il+1))

考虑答案取到 i − l + 1 i-l+1 il+1的情况有哪些
i − l + 1 < = s l [ i ] i-l+1<=sl[i] il+1<=sl[i] i − s l [ i ] + 1 < = l i-sl[i]+1<=l isl[i]+1<=l
i i i每次+1, s l [ i ] sl[i] sl[i]每次最多+1,所以一定是单调不降的

所以可以二分出一个pos,使得 i < = p o s i<=pos i<=pos的时候取 i − l + 1 i-l+1 il+1,往后的取 s l [ i ] sl[i] sl[i],可以用ST表轻松维护

code:

#include<bits/stdc++.h>
#define N 400050
using namespace std;
struct A {
    int ch[27], len, fa;
} a[N];
int lst = 1, tot = 1;
void insert(int c) {
    int p = lst, np = ++ tot; lst = np;
    a[np].len = a[p].len + 1;
    while(p && !a[p].ch[c]) a[p].ch[c] = np, p = a[p].fa;
    if(!p) a[np].fa = 1;
    else {
        int q = a[p].ch[c];
        if(a[q].len == a[p].len + 1) a[np].fa = q;
        else {
            int clone = ++ tot; a[clone] = a[q];
            a[clone].len = a[p].len + 1;
            while(p && a[p].ch[c] == q) a[p].ch[c] = clone, p = a[p].fa;
            a[np].fa = a[q].fa = clone;
        }
    }
}
char st[N], stt[N];
int sl[N];
void solve() {
    int n = strlen(st + 1), p = 1;
    for(int i = 1; i <= n; i ++) {
        int c = st[i] - 'a';
        if(a[p].ch[c]) sl[i] = sl[i - 1] + 1, p = a[p].ch[c];
        else {
            while(p && !a[p].ch[c]) p = a[p].fa;
            if(!p) p = 1;
            else sl[i] = a[p].len + 1, p = a[p].ch[c];
        }
    }
}
int mx[N][20], q;
int query(int l, int r) {
    if(l > r) return 0;
    int k = log2(r - l + 1);
    return max(mx[l][k], mx[r - (1 << k) + 1][k]);
}
int find(int l, int r) { r ++;
    int L = l;
    while(l + 1 < r) {
        int mid = (l + r) >> 1;
        if(mid - sl[mid] + 1 >= L) r = mid;
        else l = mid;
    }
    return r;
}
int main() {
    scanf("%s", st + 1); scanf("%s", stt + 1);
    int n = strlen(stt + 1);
    for(int i = 1; i <= n; i ++) insert(stt[i] - 'a');
    n = strlen(st + 1);
    solve();
    for(int i = 1; i <= n; i ++) mx[i][0] = sl[i];
    for(int j = 1; j <= 18; j ++)
        for(int i = 1; i + (1 << j) - 1 <= n; i ++)
            mx[i][j] = max(mx[i][j - 1], mx[i + (1 << (j - 1))][j - 1]);
//    for(int i = 1; i <= n; i ++) printf("%d ", sl[i]); printf("\n");
    scanf("%d", &q);
    while(q --) {
        int l, r;
        scanf("%d%d", &l, &r);
        int pos = find(l, r);
    //    printf("%d %d %d   ", pos, l, r);
        printf("%d\n", max(pos - l, query(pos, r)));
    }
    return 0;
}
posted @ 2021-09-07 21:17  lahlah  阅读(41)  评论(0编辑  收藏  举报