题意:
给定字符串S,求格式为ABACA的字符串分割(A,B,C皆为S的子串)A的最长长度。
思路:
ABACA格式:说明分割方法要使得前缀同后缀相同并能在前后缀部分外找到与前后缀相同的子串。
以S为母串S为子串进行扩展KMP处理后,如果能找到某点的Ex[i]+i==len说明我们找到了一个相同的前后缀。
注意Ex[i]的意义:S[i,...,n-1]同S的最长公共前缀。所以当我们找到一个Ex[i]+i==len时,只需在[Ex[i],len-Ex[i]-1]区间内再找到一个Ex[j]>=Ex[i]就可以说明除前缀和后缀外的部分还存在一个子串同前后缀相同。
C++代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
void GetNext( char *s , int *Next )
{
int c = 0,len = strlen(s);
Next[0] = len;
while ( s[c]==s[c+1]&&c+1<len ) c++;
Next[1] = c;
int po = 1;
for ( int i=2 ; i<len ; i++ )
{
if ( Next[i-po]+i<Next[po]+po )
Next[i] = Next[i-po];
else
{
int t = Next[po]+po-i;
if ( t<0 ) t = 0;
while ( i+t<len&&s[t]==s[i+t] ) t++;
Next[i] = t;
po = i;
}
}
}
void ExKmp( char *s1 , char *s2 , int *Next , int *Ex )
{
int c = 0,len = strlen(s1),l2 = strlen(s2);
GetNext( s2 , Next );
while ( s1[c]==s2[c]&&c<len&&c<l2 ) c++;
Ex[0] = c;
int po = 0;
for ( int i=1 ; i<len ; i++ )
{
if ( Next[i-po]+i<Ex[po]+po )
Ex[i] = Next[i-po];
else
{
int t = Ex[po]+po-i;
if ( t<0 ) t = 0;
while ( i+t<len&&t<l2&&s1[i+t]==s2[t] ) t++;
Ex[i] = t;
po = i;
}
}
}
int Next[maxn],Ex[maxn],Max[maxn<<2];
char S[maxn];
void Build( int l , int r , int rt )
{
if ( l==r )
{
Max[rt] = Ex[l];
return;
}
int lson = rt<<1;
int rson = rt<<1|1;
int mid = ( l+r )>>1;
Build ( l , mid , lson );
Build ( mid+1 , r , rson );
Max[rt] = max( Max[lson] , Max[rson] );
}
int Query( int L , int R , int l , int r , int rt )
{
if ( L>R ) return -1;
if ( L==l&&R==r ) return Max[rt];
int lson = rt<<1;
int rson = rt<<1|1;
int mid = ( l+r )>>1;
if ( R<=mid )
return Query( L , R , l , mid , lson );
else if ( L>mid )
return Query( L , R , mid+1 , r , rson );
else
return max ( Query( L , mid , l , mid , lson ) , Query( mid+1 , R , mid+1 , r , rson ) );
}
int main()
{
int Cas; scanf ( "%d" , &Cas );
while ( Cas-- )
{
scanf ( "%s" , S );
ExKmp( S , S , Next , Ex );
int ans = 0,len = strlen(S);
Build ( 0 , len-1 , 1 );
for ( int i=0 ; i<len ; i++ )
if ( i+Ex[i]==len&&Query( Ex[i] , len-Ex[i]-1 , 0 , len-1 , 1 )>=Ex[i] )
ans = max ( ans , Ex[i] );
printf ( "%d\n" , ans );
}
return 0;
}