考虑按 \(l\) 扫描线,每次向右扩展 \(r\).
考虑记录 \(f_i\) 为答案为 \(i\) 的字典序最小的 \([l,r]\)。
考虑到在 \(l,r\) 上还有一维偏序,所以只有在 \(l\) 扫到答案的 \(r\) 时再加入答案。
考虑到最长的长度不超过 \(\sqrt n\),可以二分找到 \(LCP\),那么复杂度为 \(O(n\sqrt n log)\)
点击查看代码
//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N 30000
#define M 400
unsigned ll key[M];
unsigned ll H[N][M];
int n;
int lim;
char s[N];
int li[N],ri[N];
using std::vector;
using std::pair;
#define pii pair<int,int>
int ans = 0;
#define mp std::make_pair
vector<pii>R[N];
#define mid ((L + R) >> 1)
inline int cmp(int l,int r,int x,int y){//cmp [l,r] [x,y] 1 : > 0 : = -1 : <
// std::cout<<"CHECK"<<"("<<l<<","<<r<<") "<<"("<<x<<","<<y<<")"<<"\n";
if(x == 0)return 1;if(x == n + 1)return -1;
int L = 0,R = std::min(r - l + 1,y - x + 1),res = 0;
while(L <= R){
if(H[l][mid] == H[x][mid])
res = mid,L = mid + 1;
else
R = mid - 1;
}
// std::cout<<"LCP "<<res<<"\n";
if(res != std::min(r - l + 1,y - x + 1)){
if(s[l + res] < s[x + res])return -1;else return 1;
}else{
int len1 = r - l + 1,len2 = y - x + 1;
if(len1 == len2)return 0;
if(len1 < len2)return -1;
if(len1 > len2)return 1;
}
}
int main(){
srand(time(0));
scanf("%d",&n);
lim = sqrt(2 * n);
for(int i = 1;i <= lim;++i)
key[i] = rand();
scanf("%s",s + 1);
for(int i = 1;i <= n;++i)
for(int j = 1;j <= lim;++j){
H[i][j] = H[i][j - 1] + key[j] * s[i + j - 1];
// std::cout<<i<<" "<<j<<" "<<H[i][j]<<"\n";
}
for(int i = 1;i <= n;++i)
li[i] = ri[i] = n + 1;
for(int i = 1;i <= n;++i){
int k = 0;
for(int j = 1;j <= M && i + j - 1 <= n;++j){
int l = i,r = i + j - 1;
while(k <= n && cmp(l,r,li[k],ri[k]) == 1)++k;
// std::cout<<i<<" "<<j<<" "<<k<<"\n";
ans = std::max(ans,k);
R[r].push_back(mp(l,k));
}
for(auto U : R[i]){
int l = U.first;
int k = U.second;
int r = i;
if(cmp(l,r,li[k],ri[k]) == -1)li[k] = l,ri[k] = r;/*,std::cout<<"F_"<<k<<"->"<<"("<<l<<","<<r<<")"<<"\n";*/
}
}
std::cout<<ans<<"\n";
}