[BZOJ2342] SHOI2011 双倍回文 manacher O(n)

瞎扯

今天刚讲了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 ;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值