BUPT2017 wintertraining(15) #5F

HDU - 3294

题意

给定字母x,字符串变换一下: 'x'-1 -> 'z', ‘x’->‘a’, ‘x’+1->‘b’, ..., 求对应的字符串的最长的回文串。

题解

求最长回文串的O(n)的算法:Manacher算法

算法过程:

  1. 用’#‘号把每个字符分隔开,且开头结尾都是’#‘。
  2. RL[i]为以i为中心的最长回文最右的字符与i的距离。
  3. 已经求过的回文串中,右端点最大的回文串的中心为p。
  4. 求当前的RL[i]时,若 i 在最大右端点的左边,则RL[i] 初始值为min(RL[j],最大右端点-i),j是以p为中心,i对称的点。否则RL[i]=1。
  5. 再直接扩展RL[i],同时维护p。

代码

#include <cstdio>
#include <algorithm>
#define N 200002
using namespace std;
char c,s[N<<1];
int RL[N<<1];
int Manacher(){
	int i,p=0,q=0;
	for(i=0;s[i];i++);
	for(i;i>=0;i--) s[i*2+1]=s[i],s[i*2]='#';
	for(i=0;s[i];i++){
		if(RL[p]+p>i) RL[i]=min(RL[p*2-i],RL[p]+p-i);
		else RL[i]=1;
		while(s[i-RL[i]]&&s[i-RL[i]]==s[i+RL[i]]) RL[i]++;
		if(i+RL[i]>p+RL[p]) p=i;
		if(RL[i]>RL[q]) q=i; //q是最长的回文串的中点。
	}
	return q;
}
int main() {
	while(~scanf(" %c%s",&c,s)){
		int q=Manacher();
		int i=q-RL[q]+1,j=q+RL[q]-1;
		if(s[i]=='#')i++,j--;
		if(RL[q]>2){
			printf("%d %d\n",i/2,j/2);
			for(;i<=j;i+=2) printf("%c",(s[i]-c+26)%26+'a');
		}else printf("No solution!");
		puts("");
	}
	return 0;
}


┆凉┆暖┆降┆等┆幸┆我┆我┆里┆将┆ ┆可┆有┆谦┆戮┆那┆ ┆大┆始┆ ┆然┆
┆薄┆一┆临┆你┆的┆还┆没┆ ┆来┆ ┆是┆来┆逊┆没┆些┆ ┆雁┆终┆ ┆而┆
┆ ┆暖┆ ┆如┆地┆站┆有┆ ┆也┆ ┆我┆ ┆的┆有┆精┆ ┆也┆没┆ ┆你┆
┆ ┆这┆ ┆试┆方┆在┆逃┆ ┆会┆ ┆在┆ ┆清┆来┆准┆ ┆没┆有┆ ┆没┆
┆ ┆生┆ ┆探┆ ┆最┆避┆ ┆在┆ ┆这┆ ┆晨┆ ┆的┆ ┆有┆来┆ ┆有┆
┆ ┆之┆ ┆般┆ ┆不┆ ┆ ┆这┆ ┆里┆ ┆没┆ ┆杀┆ ┆来┆ ┆ ┆来┆