hdu5304

来源:互联网 发布:小区宽带计费软件 编辑:程序博客网 时间:2024/04/29 15:30

BC的题出的真的太木有层次了。。让我这种渣渣怎么活。。不知道以后有dv1,dv2后会不会有所改善。。
首先,要求出所有的回文子串,因为子串长度最大为20w,所以我们得用接近线性的方法来求才行。此时,Manacher算法就派上了用场。它能以O(n)的效率求出以每个字符为中心的最长回文子串的长度。
Manacher具体的思想还是不难懂的,只要好好参悟下,给个链接:http://blog.sina.com.cn/s/blog_70811e1a01014esn.html
对于此题,我们先用Manacher方法求出所有p[i],然后遍历这个数组,找出所有包含前缀和后缀的最长子串位置。
对于所有前缀和后缀的位置,如果前缀所涉及到最长子串位置与后缀的最长子串位置有重合,那么不符合条件。否则就判断它们中间位置的最长子串长度是否大于等于中间子串的长度即可。

#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<iomanip>#include<vector>#include<time.h>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<map>#include<set>#include<limits.h>//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff#define FOR(i,a) for((i)=0;i<(a);(i)++)#define MEM(a) (memset((a),0,sizeof(a)))#define sfs(a) scanf("%s",a)#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a);#define pf(a) printf("%d\n",a)#define pfI(a) printf("%I64d\n",a)#define pfs(a) printf("%s\n",a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)#define for1(i,a,b) for(int i=(a);i<b;i++)#define for2(i,a,b) for(int i=(a);i<=b;i++)#define for3(i,a,b)for(int i=(b);i>=a;i--)#define MEM1(a) memset(a,0,sizeof(a))#define MEM2(a) memset(a,-1,sizeof(a))const double PI = acos(-1.0);template<class T> T gcd(T a, T b) {    return b ? gcd(b, a % b) : a;}template<class T> T lcm(T a, T b) {    return a / gcd(a, b) * b;}template<class T> inline T Min(T a, T b) {    return a < b ? a : b;}template<class T> inline T Max(T a, T b) {    return a > b ? a : b;}#define ll long longusing namespace std;int n,m;#define M 1000010#define N 110050char ch[N];char s[N];int tot;int p[N];void Manacher(){    memset(p,0,sizeof p);    for(int i=1,j=0,k;i<tot;){        while(i-j-1>=0 && i+j+1<tot && s[i-j-1] == s[i+j+1])            j++;        p[i] = j;        for(k=1;k<=j && i-k>=0 && p[i]-k!=p[i-k];k++)            p[i+k] = Min(p[i-k],p[i]-k);        i += k;        j = Max(j-k,0);    }    vector<int> top;    vector<int> tail;    for(int i=1;i<tot-1;i++){        if(i-p[i] == 0) top.push_back(i); //记录所有包含前缀的位置        if(i+p[i] == tot-1) tail.push_back(i);  //记录所有包含后缀的位置    }    int size1 = (int)top.size();    int size2 = (int)tail.size();    int flag = 0;    for(int i=0;i<size1;i++){        for(int j=0;j<size2;j++){            int s1 = top[i]+p[top[i]]+1; //中间子串的起始位置            int s2 = tail[j]-p[tail[j]]-1;//中间子串的终止位置            if(s1>s2) continue; //如果有相交,则不符合条件            int mid = (s1+s2)/2;    //否则计算中间子串的中间位置            if(p[mid]>=mid-s1)  //p[mid]为中间位置的最长回文子串半径,mid-s1为中间子串的半径,如果前者大于后者                    //则说明中间的这个子串也是一个回文子串,至此,该字符串被分割成为了三个回文子串                flag=1;            if(flag) break;        }        if(flag) break;    }    if(flag)        printf("Yes\n");    else        printf("No\n");}int main() {#ifndef ONLINE_JUDGE    freopen("in.txt", "r", stdin);//  freopen("out.txt", "w", stdout);#endif    int t;    sf(t);    while(t--){        sfs(ch);        int len = strlen(ch);        tot=0;        s[tot++] = '#';        for(int i=0;i<len;i++){            s[tot++] = ch[i];            s[tot++] = '#';        }        Manacher();//      for(int i=0;i<tot;i++)//          printf("%d ",p[i]);//      puts("");    }    return 0;}
0 0
原创粉丝点击