POJ-3693 Maximum repetition substring (后缀数组)
POJ-3693 Maximum repetition substring (后缀数组)
题意:求连续重复次数最多的子串
一个连续重复子串可以描述为\(l,r,len\)(端点,循环节长度)
\(O(n^2)\):直接枚举\(l,len\),然后求\(l\)和\(l+len\)的\(LCP\),就能得到最大的\(r\)
考虑不一一枚举\(l\)
枚举\(len\)之后,从一个点开始向前取\(LCP\),向后取\(LCP\),就能够拼出一个完整的循环串
用这种方法可以去掉大量重复枚举,只枚举\(l=k\cdot len (k\in Z)\)
用ST表查询可以做到\(O(n \ln n)\)
细节似乎蛮多的,代码很烦
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cctype>
#include<cstring>
#include<cassert>
using namespace std;
namespace Folder{
#define reg register
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
char IO;
//template <class T=int>
int rd(){
int s=0;
int f=0;
while(!isdigit(IO=getchar())) f|=(IO=='-');
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
}
using namespace Folder;
const int N=1e5+10,INF=1e9;
int n;
char s[N];
int kase;
#define ms(a) memset(a,0,sizeof a)
struct Sparse_Table{
int s[20][N],Log[N];
void PreMake(const int *a){
rep(i,2,n) Log[i]=Log[i>>1]+1;
rep(i,1,n) s[0][i]=a[i];
rep(i,1,Log[n]) {
int len=(1<<(i-1));
rep(j,1,n-(1<<i)+1) s[i][j]=min(s[i-1][j],s[i-1][j+len]);
}
}
int Que(int l,int r) {
int d=Log[r-l+1];
return min(s[d][l],s[d][r-(1<<d)+1]);
}
};
struct Suffix_Array{
int cnt[N],rk[N<<1],sa[N],tmp[N],lcp[N];
Sparse_Table ST;
void PreMake(char *s){
n=strlen(s+1);
memset(cnt,0,800);
rep(i,1,n) cnt[(int)s[i]]++;
rep(i,1,200) cnt[i]+=cnt[i-1];
rep(i,1,n) rk[i]=cnt[(int)s[i]],sa[i]=i;
rep(i,n+1,n*2) rk[i]=0;
for(reg int k=1;k<=n;k<<=1) {
rep(i,0,n) cnt[i]=0;
rep(i,1,n) cnt[rk[i+k]]++;
rep(i,1,n) cnt[i]+=cnt[i-1];
drep(i,n,1) tmp[cnt[rk[i+k]]--]=i;
rep(i,0,n) cnt[i]=0;
rep(i,1,n) cnt[rk[i]]++;
rep(i,1,n) cnt[i]+=cnt[i-1];
drep(i,n,1) sa[cnt[rk[tmp[i]]]--]=tmp[i];
rep(i,1,n) tmp[sa[i]]=tmp[sa[i-1]]+(rk[sa[i]]!=rk[sa[i-1]]||rk[sa[i]+k]!=rk[sa[i-1]+k]);
rep(i,1,n) rk[i]=tmp[i];
}
int h=0;
memset(lcp,0,(n+2)*4);
rep(i,1,n) {
int j=sa[rk[i]-1];
if(h) h--;
while(i+h<=n && j+h<=n && s[i+h]==s[j+h]) h++;
lcp[rk[i]-1]=h;
}
ST.PreMake(lcp);
}
int Que(int x,int y){
if(x==y) return n-x+1;
if(rk[x]>rk[y]) swap(x,y);
return ST.Que(rk[x],rk[y]-1);
}
}SA,RSA;
Sparse_Table ST;
int main(){
while(~scanf("%s",s+1) && s[1]!='#') {
n=strlen(s+1);
SA.PreMake(s),reverse(s+1,s+n+1),RSA.PreMake(s);
ST.PreMake(SA.rk);
int ans=0,st,ed;
rep(i,1,n) {
rep(j,1,n) {
int a=i*(j-1)+1,b=i*j+1;
if(b>n) break;
int len=SA.Que(a,b)+RSA.Que(n-a+1,n-b+1)-1; // 向前和向后找LCP
if(len<0) continue;
if(len<i) continue;
int l=a-RSA.Que(n-a+1,n-b+1)+1,r=b+SA.Que(a,b)-1;
int p=SA.sa[ST.Que(l,r-(len/i+1)*i+1)];
l=p,r=p+(len/i+1)*i-1;
if(len/i+1>ans) ans=len/i+1,st=l,ed=r;
else if(len/i+1==ans && (SA.rk[st]>SA.rk[l]||(SA.rk[st]==SA.rk[l]&& r-l+1<ed-st+1) ) ) st=l,ed=r;
}
}
if(!ans) ans=1,st=SA.sa[1],ed=SA.sa[1];
reverse(s+1,s+n+1);
printf("Case %d: ",++kase);
rep(i,st,ed) putchar(s[i]);
putchar('\n');
}
}