题意
f
(
i
)
f(i)
f(i) 表示将字符串 s
分为 i
段,每一段的最长公共前缀的最长长度。
求 f ( l ) , f ( l + 1 ) . . . f ( r ) f(l),f(l+1)...f(r) f(l),f(l+1)...f(r)。
解题思路
假如
s
s
s 某个前缀
t
t
t 在
s
s
s 中最多可以找到
x
x
x 个不相交和
t
t
t 相同的子串,比如ababababab
,对于前缀abab
,最多可以找到 2
个不相交的和 abab
相同的子串。
所以分成小于等于 x x x 段的结果都可以使用 t t t 的长度去更新,所以我们只需要枚举字符串的所有前缀。
考虑对原串构建后缀自动机,在后缀树上用启发式合并维护 endpos
集合,每 dfs
到表示前缀的节点,我们按照上方思路贪心的找到最多的不相交的子串(位置靠前优先选)每个 endpos
集合最大为 n
,每次最多跳
⌊
n
l
e
n
(
p
r
e
f
i
x
)
⌋
\left \lfloor \frac{n}{len(prefix)} \right \rfloor
⌊len(prefix)n⌋ 次,总共最多
∑
i
=
1
n
⌊
n
i
⌋
\sum_{i=1}^{n}\left \lfloor \frac{n}{i} \right \rfloor
∑i=1n⌊in⌋ 次,每次跳使用lower_bound
,时间复杂度
l
o
g
(
n
)
log(n)
log(n),复杂度约等于
O
(
n
×
l
n
(
n
)
×
l
o
g
(
n
)
)
O(n\times ln(n)\times log(n))
O(n×ln(n)×log(n)),启发式合并复杂度
O
(
n
×
l
o
g
2
(
n
)
)
O(n\times log^{2}(n))
O(n×log2(n))。
总时间复杂度 O ( n × l o g 2 ( n ) ) O(n\times log^2(n)) O(n×log2(n))。
AC_Code
//
// Created by liuhao.
//
#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
template<class T>
struct Suffix_Automaton {
int tot = 1, last = 1;
struct Node {
signed len, fa, fipos;
int ch[26];
};
vector<Node> node;
int n;
Suffix_Automaton(T &s) : n(s.size() - 1), node(2 * s.size()) {
for (int i = 1; i < s.size(); i++)extend(s[i]-'a');
}
void extend(int c) {
int p = last, np = last = ++tot;
node[np].len = node[p].len + 1;
node[np].fipos = node[np].len;
for (; p && !node[p].ch[c]; p = node[p].fa)node[p].ch[c] = np;
if (!p)node[np].fa = 1;
else {
int q = node[p].ch[c];
if (node[q].len == node[p].len + 1)node[np].fa = q;
else {
int cp = ++tot;
node[cp] = node[q], node[cp].len = node[p].len + 1;
node[cp].fipos=0;
node[q].fa = node[np].fa = cp;
for (; p && node[p].ch[c] == q; p = node[p].fa)node[p].ch[c] = cp;
}
}
}
int size() { return tot; }
Node operator[](int i) {
return node[i];
}
};
auto main() -> signed {
ios;
int T;
cin>>T;
while(T--){
int n,l,r;
cin>>n>>l>>r;
string s;
cin>>s;
s=' '+s;
Suffix_Automaton<string>suf(s);
vector<vector<int>>g(suf.size()+1);
for(int i=2;i<=suf.size();i++){
g[suf[i].fa].push_back(i);
}
vector<int>d(n+1);
vector<set<int>>S(suf.size()+1);
auto dfs=[&](auto dfs,int x)->void{
for(auto i:g[x]){
dfs(dfs,i);
if(S[i].size()>S[x].size())S[i].swap(S[x]);
for(auto j:S[i]){
S[x].insert(j);
}
}
if(suf[x].fipos!=0){
S[x].insert(suf[x].fipos);
int last=0;
int res=0;
for(auto i=S[x].begin();i!=S[x].end();){
auto t=S[x].lower_bound(last+suf[x].len);
if(t==S[x].end())break;
last=*t;
res++;
}
d[res]=max(suf[x].len,d[res]);
}
};
dfs(dfs,1);
for(int i=n-1;i>=1;i--){
d[i]=max(d[i+1],d[i]);
}
for(int i=l;i<=r;i++){
cout<<d[i]<<' ';
}
cout<<endl;
}
return 0;
}