题意 : 给定一个字符串L , 已知这个字符串是有某个字符串S重复R次得到的,求R的最大值。
思路 : 假设字符串S 的长度为 l ,那么先枚举所有 l 满足 len % l == 0 , 然后在验证 LCP( 0 , l ) = len - l , 如果成立 , 那么 len / l 就是答案 。
为什么这样就能成立 ? 根据 LCP( 0 , l ) == len - l ,那么我们可以得到一些等式 :
L( 0 , l ) = L( l , 2 * l ) , L( l , 2 * l ) = L( 2 * l , 3 * l ) ... L(len-2*l,len-*l) = L( len - l , len )
我们定义 L( a , b ) 为 字符串L的子串 : L[a] , L[a+1] ... L[b-1]
所以我们可以得到 L( 0 , l ) = L ( l , 2 * l ) = ... L( len-l , len ) , 所以当满足上述条件时 , 字符串L就是由长度为l的前缀重复得到。
那么解法可以有KMP,因为next数组求的就是这个,不过最近学SA,还是用SA写。不过写的时候要几点注意的,求LCP不要用rmq去求,否则会MLE。因为求的LCP都是和后缀0有关的 , 所以先求出后缀0的rank然后往前,往后推一遍就行了。然后不能用da去写,会TLE ... ( 听说暴力都没卡住,结果卡da卡得死死的 ) 。最后用了dc3才勉强过的。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std ;
#define maxn 1000005
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int c0(int *r,int a,int b)
{return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];}
int c12(int k,int *r,int a,int b)
{if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];}
void sort(int *r,int *a,int *b,int n,int m)
{
int i;
for(i=0;i<n;i++) wv[i]=r[a[i]];
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) b[--ws[wv[i]]]=a[i];
return;
}
void dc3(int *r,int *sa,int n,int m)
{
int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
r[n]=r[n+1]=0;
for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i;
sort(r+2,wa,wb,tbc,m);
sort(r+1,wb,wa,tbc,m);
sort(r,wa,wb,tbc,m);
for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
if(p<tbc) dc3(rn,san,tbc,p);
else for(i=0;i<tbc;i++) san[rn[i]]=i;
for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3;
if(n%3==1) wb[ta++]=n-1;
sort(r,wb,wa,ta,m);
for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
for(i=0,j=0,p=0;i<ta && j<tbc;p++)
sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
for(;i<ta;p++) sa[p]=wa[i++];
for(;j<tbc;p++) sa[p]=wb[j++];
return;
}
int Rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) Rank[sa[i]]=i;
for(i=0;i<n;height[Rank[i++]]=k)
for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int sa[maxn*3] , r[maxn*3] ;
char str[maxn] ;
// lcp[i] 为 后缀 0 和 后缀 sa[i] 的 lcp
int lcp[maxn] ;
int main(){
while( scanf( "%s" , str )!= EOF ) {
if( strcmp( str , "." ) == 0 ) break;
int len = strlen( str ) ;
for( int i = 0 ; i < len ; i ++ ) r[i] = str[i] ; r[len] = 0 ;
dc3( r , sa , len + 1 , 200 ) ;
calheight( r , sa , len ) ;
int ans = 1 ;
// 后缀0的Rank
int r = Rank[0] ;
lcp[r] = len - sa[r] ;
for( int i = r + 1 ; i <= len ; i ++ ) {
lcp[i] = min( lcp[i-1] , height[i] ) ;
}
for( int i = r ; i > 1 ; i -- ) {
lcp[i-1] = min( lcp[i] , height[i] ) ;
}
for( int i = 1 ; i < len ; i ++ ) {
if( len % i == 0 && lcp[Rank[i]] == len - i ) {
ans = len / i ;
break;
}
}
printf( "%d\n" , ans ) ;
}
return 0 ;
}