您的位置:首页 > 其它

hdu 5340 Three Palindromes

2015-08-02 19:57 302 查看
给一个串,问是否能把它拆为三个回文串。

用Manachar计算以每个字符为中心的最长回文串长度,然后枚举头尾,判断中心是否为回文串。

理解了一下manachar,它从左往右扫,记录每个位置为中心的最长回文串长度,维护了当前回文串能到达的最右边的位置和回文串长度、中心。根据这些信息以及对称性,就可以推知下一个位置回文长度至少是多少。虽然有两重循环,但内循环只会执行O(n)次,因为当前回文串能到达的最右边是单调递增的。

官方题解给的二进制压位优化没有弄明白,求大神解释。。不压位写好点也是能过的。

然后一个学弟把压位看明白了,其实想明白就简单了。。就是把32个0或1的位压到一个int里,一次性比较32位。。优化常数。。就不实现了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <stack>

using namespace std;

const int MAX = 20010;

int len, p[2*MAX];  
char str[2*MAX], newstr[2*MAX];  
  
void change(){
     int i;  
     newstr[0] = '@';  
     newstr[1] = '#';  
     for (i = 0; i < len; i++){  
         newstr[2*i + 2] = str[i];  
         newstr[2*i + 3] = '#';  
     }  
     newstr[2*len + 2] = '\0';  
     return ;  
}  

void Manacher(){  
     int i, j, id, maxid = 0, ans = 1;  
     len = 2 * len + 2;  
     for (i = 0; i < len; i++){  
         if (maxid > i){  
             p[i] = min(p[2*id - i], maxid - i);  
         }  
         else{  
              p[i] = 1;  
         }  
         while (newstr[i+p[i]] == newstr[i-p[i]])  
                p[i]++;  
         if (p[i] + i > maxid){  
             maxid = p[i] + i;  
             id = i;  
         }  
         if (ans < p[i])  
             ans = p[i];  
     }
     return ;  
}  

int head[MAX];
int tail[MAX];  

int main(){
    int t;
    cin>>t;
    while (t--){  
        scanf("%s", &str);
        len = strlen(str);  
        change();  
        Manacher();
        int headCnt=0;
        int tailCnt=0;
        for(int i=2;i<=len-2;i++){
            if(p[i]==i){
                head[headCnt++]=i;
            }
            if(p[i]==len-i){
                tail[tailCnt++]=i;
            }
        }
        
        bool ok=0;
        for(int i=0;i<headCnt;i++){
            for(int j=0;j<tailCnt;j++){
                int l=head[i]+p[head[i]] ;
                int r=tail[j]-p[tail[j]] ;
                if(l>r)continue;
                
                int mid = (head[i]+p[head[i]] + tail[j]-p[tail[j]])>>1;
                if(l==r&&newstr[mid]=='#')continue;
                if(p[head[i]]*2-1+p[tail[j]]*2-1+p[mid]*2-1>=len+1){
                    ok=1;break;
                }
            }
            if(ok)break;
        }
        
        if(ok){
            cout<<"Yes"<<endl;
        }else{
            cout<<"No"<<endl;
        }
    }  
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: