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[i−sl[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],i−l+1))
考虑答案取到
i
−
l
+
1
i-l+1
i−l+1的情况有哪些
i
−
l
+
1
<
=
s
l
[
i
]
i-l+1<=sl[i]
i−l+1<=sl[i]即
i
−
s
l
[
i
]
+
1
<
=
l
i-sl[i]+1<=l
i−sl[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 i−l+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;
}