
比较朴素的想法就是枚举子串的长度$l$并找到最大的$k$,这样做是$O(n^3)$的
我们可以用后缀数组优化这个过程,同样是枚举$l$,只不过我们可以把所有后缀按$height\geq l$的连续段分组,先扫一遍找出所有长度$\geq l$的出现多次的子串,然后按$sa$排序,贪心地从前往后取,看最大能取到的$k$是什么,就做完了
快排估计会超时,所以这里我们可以用计数排序做到$O(n^2)$的总时间复杂度
p.s.说实话一开始被$n=10^4$吓到了,但实际上这个平方不是满的,又有$\text{2s}$时限,所以不虚==
#include<stdio.h>
#include<string.h>
struct pr{
int c[2],id;
pr(int a=0,int b=0,int d=0){c[0]=a;c[1]=b;id=d;}
}p[16010],q[16010];
bool operator!=(pr a,pr b){return a.c[0]!=b.c[0]||a.c[1]!=b.c[1];}
int rk[32010],sa[16010],h[16010],c[16010],n;
int max(int a,int b){return a>b?a:b;}
void sort(int n,int f){
int i,m;
memset(c,0,sizeof(c));
m=0;
for(i=1;i<=n;i++){
m=max(m,p[i].c[f]);
c[p[i].c[f]]++;
}
for(i=1;i<=m;i++)c[i]+=c[i-1];
for(i=n;i>0;i--)q[c[p[i].c[f]]--]=p[i];
for(i=1;i<=n;i++)p[i]=q[i];
}
char s[16010];
void suf(){
int i,l,m;
for(i=1;i<=n;i++)rk[i]=s[i];
for(l=1;l<=n;l<<=1){
for(i=1;i<=n;i++)p[i]=pr(rk[i],rk[i+l],i);
sort(n,1);
sort(n,0);
m=0;
for(i=1;i<=n;i++){
if(p[i]!=p[i-1])m++;
rk[p[i].id]=m;
}
}
for(i=1;i<=n;i++)sa[rk[i]]=i;
l=0;
for(i=1;i<=n;i++){
if(l)l--;
while(s[i+l]==s[sa[rk[i]-1]+l])l++;
h[rk[i]]=l;
}
}
int main(){
int las,i,l,k,L,K,M,ans;
scanf("%s",s+1);
n=strlen(s+1);
suf();
L=K=ans=0;
for(l=1;l<=n/2;l++){
memset(c,0,sizeof(c));
M=1;
for(i=2;i<=n;i++){
if(h[i]>=l)
c[sa[i-1]]=c[sa[i]]=M;
else
M++;
}
M=0;
for(i=1;i<=n;i++){
if(c[i]){
M++;
p[M]=pr(c[i],i);
}
}
sort(M,1);
sort(M,0);
las=p[1].c[1];
k=1;
p[M+1].c[0]=0;
for(i=2;i<=M+1;i++){
if(p[i].c[0]!=p[i-1].c[0]){
if(k*l>K*L){
K=k;
L=l;
ans=las;
}
k=1;
las=p[i].c[1];
}else if(las+l<=p[i].c[1]){
k++;
las=p[i].c[1];
}
}
}
if(ans==0){
puts("-1");
return 0;
}
printf("%d\n",L*K);
for(i=ans;i<ans+L;i++)putchar(s[i]);
}