瞎扯
今天刚讲了manacher,顺手找了道题来练练。
有个细节没有注意到,1A无缘·····
网上很多人都是nlogn写法,然而这题O(n)也可以做,只要在manacher里添加一个判断就好了,原理是一样的。
题目
BZOJ2342
题意:中文题自己看去=。=
##分析:
这题要我们求最长的两个连续回文串,并且这两个回文串长度为偶数。易知:两个回文串拼接起来还是一个回文串。
在求出前一个回文串后,后一个的回文串一定由前一个对称得到,那么只需要在if( mx > i )之内,顺便判断对称的两个回文串是否相交,相交则更新答案,详细看代码。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int N , cclen;
char cc[2000010];
int pal[2000010] , ans = 0 ;
void manacher(){
int id = 0 , mx = 0 ;
for( register int i = 2 ; i <= cclen ; i += 2 ){
//此处i+=2 因为只有以#为对称中心的回文串长度为偶数
if( mx > i ){
pal[i] = min( mx - i , pal[2*id-i] ) ;
if( pal[i] >= i - id + 1 )
ans = max( ans , (i - id ) << 1 ) ;
}
else
pal[i] = 1 ;
while( cc[i + pal[i]] == cc[i - pal[i]] )
pal[i]++ ;
if( pal[i] + i > mx ){
mx = pal[i] + i ;
id = i ;
}
}
}
int main(){
scanf( "%d" , &N ) ;getchar();
for( cclen = 3 ; N!=0 ; cclen+=2 , N-- ){
cc[cclen] = getchar() ;
cc[cclen+1] = '#' ;
}
cclen--;
cc[2] = '#' , cc[1] = '+' ;
manacher() ;
printf( "%d" , ans ) ;
return 0 ;
}