hdu5340--Three Palindromes(Mannacer算法)

题目链接:点击打开链接

题目大意:给出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 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值