题目描述
题解
首先求出来sa和height
然后其实就是暴力计算一下每一个后缀向后延伸多远。
注意要去掉重复的,也就是说要从每一个最长的那个后缀开始,并且对于每一个后缀,要从大到小合并。
时间复杂度
O(nlogn+n2)
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 3005
char s[N];
int n,m;
int *x,*y,X[N],Y[N],c[N],sa[N],height[N],rank[N];
int cnt[N][N];
void build_sa()
{
m=100;
x=X,y=Y;
for (int i=0;i<m;++i) c[i]=0;
for (int i=0;i<n;++i) ++c[x[i]=s[i]];
for (int i=1;i<m;++i) c[i]+=c[i-1];
for (int i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
for (int k=1;k<=n;k<<=1)
{
int p=0;
for (int i=n-k;i<n;++i) y[p++]=i;
for (int i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
for (int i=0;i<m;++i) c[i]=0;
for (int i=0;i<n;++i) ++c[x[y[i]]];
for (int i=1;i<m;++i) c[i]+=c[i-1];
for (int i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1,x[sa[0]]=0;
for (int i=1;i<n;++i)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&(sa[i-1]+k<n?y[sa[i-1]+k]:-1)==(sa[i]+k<n?y[sa[i]+k]:-1)?p-1:p++;
if (p>n) break;
m=p;
}
}
void build_height()
{
for (int i=0;i<n;++i) rank[sa[i]]=i;
int k=0;height[0]=0;
for (int i=0;i<n;++i)
{
if (!rank[i]) continue;
if (k) --k;
int j=sa[rank[i]-1];
while (i+k<n&&j+k<n&&s[i+k]==s[j+k]) ++k;
height[rank[i]]=k;
}
}
int main()
{
scanf("%d\n",&n);scanf("%s",s);
build_sa();
build_height();
for (int i=0;i<n;++i)
{
int Max=height[i+1];
if (Max<=height[i]) continue;
for (int j=i+1;j<=n;++j)
{
if (height[j]<Max)
{
cnt[i][Max]=j-i;
Max=height[j];
}
if (Max<=height[i]) break;
}
}
for (int i=0;i<n;++i)
for (int j=height[i+1];j>height[i];--j)
cnt[i][j]=max(cnt[i][j],cnt[i][j+1]);
for (int i=0;i<n;++i)
for (int j=1;j<=height[i+1];++j)
if (cnt[i][j]) printf("%d\n",cnt[i][j]);
}