题目链接:点击打开链接
题目大意:给出T个字符串,问每个字符串是不是由三个回文串组成,是输出Yes,否则No
n*n的复杂度竟然可以过啊,,,,,,,,
用Mannacer直接计算出以每一位为中心的最长回文串,然后求出pre[i](1~i)是否为回文串,suf[i](i~len-1)是否为回文串,然后枚举第二段回文串的中点,只要在第二段中左侧和右侧存在同样位置的两个pre[j]和suf[j]为1,那么就证明可以
注意:因为Mannacer会使得字符串长度增加一倍,枚举中点后,遍历回文串时只遍历字符,不遍历‘#’。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#pragma comment(linker,"STACK:102400000,102400000") ;
#define maxn 50000
char str[maxn] , s[maxn] ;
int p[maxn] ;
int pre[maxn] , suf[maxn] ;
int init() {
int i = 0 , j = 0 , l = strlen(str) ;
s[j++] = '$' ;
while( i < l ) {
s[j++] = '#' ;
s[j++] = str[i] ;
i++ ;
}
s[j++] = '#' ;
s[j] = '\0' ;
return j ;
}
void Manacer(int l) {
int i , max1 = 0 , id ;
for(i = 1 ; i < l ; i++) {
if( max1 > i )
p[i] = min( p[2*id-i],max1-1 ) ;
else
p[i] = 1 ;
while( s[i-p[i]] == s[i+p[i]] )
p[i]++ ;
if( p[i]+i > max1 ) {
max1 = p[i]+i ;
id = i ;
}
}
}
int solve(int i,int len) {
int l , r , j , m ;
l = i-p[i] ;
r = i+p[i] ;
if( i%2 ) m = i-1 ;
else m = i ;
j = max( r-len+2,2-l ) ;
j = max(j,0) ;
if( (l+j)%2 ) j++ ;
for( ; l+j < m ; j += 2) {
if( pre[l+j] && suf[r-j] ) break ;
}
if( l+j < m ) return 1 ;
return 0 ;
}
int main() {
int t , m , i , j , len , l , r ;
scanf("%d", &t) ;
while( t-- ) {
scanf("%s", str) ;
len = init() ;
Manacer(len) ;
memset(pre,0,sizeof(pre)) ;
memset(suf,0,sizeof(suf)) ;
for(i = 1 ; i < len ; i++) {
if( i-p[i]+1 == 1 )
pre[ i+p[i]-2 ] = 1 ;
else if( i-p[i]+1 == 2 )
pre[ i+p[i]-1 ] = 1 ;
if( i+p[i]-1 == len-1 )
suf[ i-p[i]+2 ] = 1 ;
else if( i+p[i]-1 == len-2 )
suf[ i-p[i]+1 ] = 1 ;
}
for(i = 1 ; i <= len-i ; i++) {
if( solve(i,len) ) break ;
if( solve(len-i,len) ) break ;
}
if( i <= len-i )
printf("Yes\n") ;
else
printf("No\n") ;
}
return 0 ;
}