Girls' research HDU - 3294(Manacher转换找回文串并输出下标)

HDU - 3294

题意:给一个字符和一个串,根据一定的规则变换串,然后找出最长回文子串并输出串左右两端的下标。
思路:先把字符串转换一下,然后求mp[]。
加了其他字符后,2k ,k = 1,2,…的位置实际上是原来的k/2-1的字符。
所以求得最长半径r和对应位置pos后,
对应的原数组下标就是[(pos-r+1)/2 -1,(pos+r-1)/2-1],一边加一边减是因为加入新字符后回文字串的最外层一定是特殊字符

#include 
#include 
#include 

using namespace std;
char s1[2],s2[202020],ma[404040];
int ans,pos,mp[404040];
void manacher(int len){
	int l = 0;
	ma[l++] = '$';
	ma[l++] = '%';
	for(int i = 0;i<len;i++){
		ma[l++] =  s2[i];
		ma[l++] = '%';
	} 
	int id = 0,mx= 0;
	for(int i = 0;i<l;i++){
		mp[i] = mx>i?min(mp[2*id-i],mx-i):1;
		while(ma[i-mp[i]]==ma[i+mp[i]]) mp[i]++;
		if(i+mp[i]>mx){
			mx = i+mp[i];
			id = i;
		}
	}
}

int main(){
	while(~scanf("%s%s",s1,s2)){
		int dif = s1[0] - 'a',len = strlen(s2);
		ans = 0;
		for(int i =0;i<len;i++)
			s2[i] = (s2[i]-'a'-dif+26)%26+'a';
		manacher(len);
		for(int i = 0;i<2*len+2;i++){
			if(mp[i]-1>ans) {
				ans = mp[i] -1;
				pos = i ;
			}
		}
		if(ans == 1) printf("No solution!\n");
		else {
			printf("%d %d\n",(pos-ans+1)/2-1,(pos+ans-1)/2-1);		
			for(int i = (pos-ans+1)/2-1;i<=(pos+ans-1)/2-1;i++)		
				printf("%c",s2[i]);
			printf("\n");
		}
	}
	return 0;
}

你可能感兴趣的:(字符串—Manacher)