码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5340 Three Palindromes( 折半枚举+Manacher+记录区间 )

时间:2015-08-02 21:44:34      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:

Three Palindromes

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 809    Accepted Submission(s): 240


Problem Description
Can we divided a given string S into three nonempty palindromes?
 

Input
First line contains a single integer T20技术分享 which denotes the number of test cases.

For each test case , there is an single line contains a string S which only consist of lowercase English letters.1|s|20000技术分享
 

Output
For each case, output the "Yes" or "No" in a single line.
 

Sample Input
2 abc abaadada
 

Sample Output
Yes No
 

Source
 

Recommend
hujie


大致题意:

判断长度为2e4的字符串是否能分割成三个回文串


大致思路:

BC由于做出了这题,拿到钱了2333

Manacher处理出回文串区间, 然后得到两个数组a,b分别表示:字符0位置到a[pos]是回文串,字符len-1位置到b[pos]是回文串

然后折半枚举判a[x]~b[y]是不是回文串,用manacherO(1)就能判出来


Manacher算出了已s[x]为中心的最长回文串,然后反推到原串上的区间比较麻烦

以前推了一个公式,已经用这个公式过了三题了,说明的确没问题

int L = (i-Mp[i])>>1;
int R = (i+Mp[i]-4)>>1;



//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
using namespace std;
typedef long long ll;
#define X first
#define Y second
typedef pair<int,int> pii;

template <class T>
inline bool RD(T &ret) {
        char c; int sgn;
        if (c = getchar(), c == EOF) return 0;
        while (c != '-' && (c<'0' || c>'9')) c = getchar();
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
        ret *= sgn;
        return 1;
}
template <class T>
inline void PT(T x){
        if (x < 0) {
                putchar('-');
                x = -x;
        }
        if (x > 9) pt(x / 10);
        putchar(x % 10 + '0');
}

const int N = 20000+100;
int a[N],top1;
int b[N],top2;
char s[N];
void ini(){
        top1 = 0;
        top2 = 0;
}

int Mp[N<<1];
char Ma[N<<1];
int vs[N];
void Manacher(char s[],int len)
{
        int l = 0;
        Ma[l++] = '$';
        Ma[l++] = '#';
        for(int i=0;i<len;i++){
                Ma[l] = s[i];
                vs[i] = l++; //记录映射到原串中的位置
                Ma[l++] = '#';
        }
        Ma[l] = 0;
        int mx = 0,id = 0;
        for(int i = 1;i < l ;i ++){
                Mp[i]= mx>i? min(Mp[2*id-i],mx-i) :1;
                while(Ma[Mp[i]+i ] == Ma[i-Mp[i] ]) Mp[i]++;
                if(Mp[i]+i > mx){
                        mx = Mp[i]+i;
                        id = i;
                }
                if( Mp[i] >= 2){
                        int L = (i-Mp[i])>>1;   //逆推到原串中的区间左端点
                        int R = (i+Mp[i]-4)>>1; //逆推到原串中的区间右端点
                        if(L == 0) a[++top1] = R;
                        if(R == len-1) b[++top2] = L;
                }
        }
}
int main(){

        int T;
        RD(T);
        while(T--){
                scanf("%s",s);
                ini();
                int len = strlen(s);
                Manacher(s,len);
                sort(a+1,a+1+top1);
                sort(b+1,b+1+top2);
                bool ok = 0;
                REP(i,top1) {
                        if(ok) break;
                        for(int j = top2; j >= 1 && ok == 0;j--){
                                int l = a[i], r = b[j];
                                if( r-l <= 1) break;
                                l++,r--;
                                if( (r-l+1)&1 ){
                                        int pos = l+(r-l+1)/2;
                                        int L = (vs[pos]-Mp[vs[pos]])>>1;
                                        int R = (vs[pos]+Mp[vs[pos]]-4)>>1;
                                        if( L <= l && r <= R) ok = 1;
                                }
                                else {
                                        int pos = l+(r-l+1)/2;
                                        int p = vs[pos]-1;
                                        if( Mp[p] < 2) continue;
                                        int L = (p-Mp[p])>>1;
                                        int R = (p+Mp[p]-4)>>1;
                                        if( L <= l && r <= R) ok = 1;
                                }
                        }
                }
                if(ok) puts("Yes");
                else puts("No");
        }
        return 0;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 5340 Three Palindromes( 折半枚举+Manacher+记录区间 )

标签:

原文地址:http://blog.csdn.net/kalilili/article/details/47210305

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!