题目大意:给以一个字符串,求出来这个字符串的最长回文串,不过这个字符串不是原串,而是转换过的,转换的原则就是先给一个字符 例如 'b' 意思就是字符把字符b转换成字符 a,那么c->b, d->c.....a->z,大致就是这么个意思,然后求出最大回文串就行(回文串至少长度也得等于2)。
分析:字符转换没什么可说的,求回文串可以使用Manacher算法,主要说一下怎么用 p数组保存的信息求原来的区间,因为p保存的是扩展串的匹配数目,p[i]就是保存的最大匹配值,我们可以先求出来它的最左端是 L=i-p[i]+1, 其实这个最左端保存的值一定是一个'#',因为‘#’总会被匹配成功,实际的串的位置肯定在这个字符的右边L+1,因为扩展的时候实际字符是按照i+i+2来计算的,所以还原的时候应该是 (L+1-2)/2,也就是(i-p[i])/2;
代码如下:
==============================================================================================================
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int MAXN = 1e6+7; const int oo = 1e9+37; char s[MAXN]; int p[MAXN]; int Manacher(int len) { int id=0, Max=0; for(int i=2; i<len; i++) { p[i] = 1; if(p[id]+id > i) p[i] = min(p[id*2-i], p[id]+id-i); while( s[ i+p[i] ] == s[ i-p[i] ] ) p[i]++; if(p[id]+id < p[i]+i) id = i; if(p[Max] < p[i]) Max = i; } return Max; } int main() { char ch[10]={0}; while(scanf("%s%s", ch, s) != EOF) { int i, k=ch[0]-'a'; int N = strlen(s); for(i=N; i>=0; i--) { if(i != N) { s[i] -= k; if(s[i] < 'a') s[i] += 26; } s[i+i+2] = s[i]; s[i+i+1] = '#'; } s[0] = '$'; k = Manacher(N+N+1); if(p[k] <= 2) printf("No solution!\n"); else { int L = (k-p[k])/2, R = k+p[k]; printf("%d %d\n", L, L+p[k]-2); for(i=k-p[k]+1; i<R; i++) { if(s[i] != '#') printf("%c", s[i]); } printf("\n"); } } return 0; }