【题目描述】
操作包含两个步骤:
第一步:写一个很长的字符串(只包含小写)在纸上。例如,"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! "); else { int t1=(ans-point[ans]+2)>>1,t2=(ans+point[ans]-2)>>1; //可发现一规律:Point[i]=原以i为中心的回文子串长度+1。 printf("%d %d ",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(" "); } } return 0; }