回文串编辑

【题目描述】

操作包含两个步骤:

第一步:写一个很长的字符串(只包含小写)在纸上。例如,"abcde",而是'a'里面是不是真正的'a',这意味着如果我们定义的'b'才是真正的'a',那么我们可以推断,'c'才是真正的'b' ,'d'才是真正的'c'······,'a'才是真正的'z'。根据这一点,字符串"abcde"变为"bcdef"。

第二步:找出给定字符串中最长的回文串,回文字符串的长度必须等于或超过2。

【输入描述】

输入包含多个样例。

每个样例包含两个部分,一个字符和字符串,它们由一个空格分隔,代表真正的'a'和字符串,字符串的长度不会超过200000,所有输入字符必须为小写。

如果串的长度为n,它是从0标记为n-1。

【输出描述】

请以下两个步骤执行操作。

如果你找到一个回文串,输出它的起始位置和结束位置,下一行输出此回文串,或输出“无解!”;

如果有几个可用的答案,请选择其中最先出现的字符串。

【输入样例】

b babd

a abcd

 

【输出样例】

0 2

aza

No solution!

源代码:

#include<cstdio>
#include<cstring>
#include<algorithm> //包含min()。
using namespace std;
char keyword,s[200001],sss[200001];
int right,center,ans,num,point[200001]; //变量 right 表示当前回文子串的右边界,变量 center 表示当前回文子串的中心节点。
int main() //Manmcher算法。
{
    while (scanf("%c",&keyword)==1) //一直读入测试数据知道结束。
    {
        int key=keyword-'a'; //利用ASCII码来进行处理。
        memset(s,0,sizeof(s));
        memset(sss,0,sizeof(sss));
        memset(point,0,sizeof(point));
        right=0;
        center=0;
        num=0;
        ans=0; //全面初始化。
        char t;
        scanf("%c",&t); //除去空格。
        int length;
        scanf("%s",s);
        length=strlen(s);
        length=(length<<1)+1; //2*(string v1.0 的长度)+1=string v2.0的长度。
        for (int a=0;a<length;a++) //处理字符串。
          if (a&1)
            sss[a]=s[a>>1];
          else
            sss[a]='#';
        for (int a=0;a<length;a++) //依次处理字符。
        {
            point[a]=right>a?min(point[2*center-a],right-a):1; //如果已有回文子串右边界超过此节点,那么便有两种可能:以这个节点为中心的回文子串在这个大回文子串的范围内,或者超出这个范围。根据此理论将利用左对称点的信息来更新此节点。若不超过此节点,则只能普通处理。
            while (a>=point[a]&&sss[a+point[a]]==sss[a-point[a]]) //在允许的范围内进行边界的拓展。
              point[a]++;
            if (point[a]>num) //更新最值。
            {
                num=point[a];
                ans=a;
            }
            if (a+point[a]>right) //若新的右边界更大,则更新。
            {
                right=a+point[a];
                center=a;
            }
        }
        if (ans<=1) //无回文子串。
          printf("No solution!\n");
        else
        {
            int t1=(ans-point[ans]+2)>>1,t2=(ans+point[ans]-2)>>1; //可发现一规律:Point[i]=原以i为中心的回文子串长度+1。
            printf("%d %d\n",t1,t2);
            for (int a=t1;a<=t2;a++) //进行字符替换与处理。
                if (s[a]-key<'a')
                printf("%c",'z'+s[a]-'a'-key+1);
                else
                printf("%c",s[a]-key);
            printf("\n");
        }
    }
    return 0;
}
posted @ 2016-05-01 18:38  前前前世。  阅读(311)  评论(0编辑  收藏  举报