参考博客

AC代码(模板)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 4e5 + 10;
char s[maxn], tmp[maxn];
int dp[maxn];
char change(char x, char a){
    return (x - a + 26) % 26 + 'a';
}
///转化方式思想来自对一个圈的点标号(知道取模之后就可以自己推一下)
int main(){
    char a[5];
    while(scanf("%s%s", a, s + 1) != EOF){
    tmp[0] = '!';
    int cnt = 0;
    int len = strlen(s + 1);
    for(int i = 1; i <= len; i++){
        tmp[++cnt] = '#';
        tmp[++cnt] = s[i];
    }
    tmp[++cnt] = '#';///cnt表示新数组tmp的大小(不包括第一个元素tmp[0])
    int pos = 1, right = 2, f, e, index = 0;///很容易知道第一个元素的情况就直接枚举
    f = e = -1;///f、e是tmp数组下标映射到s数组的下标
    dp[0] = dp[1] = dp[cnt] = 1;
    ///right表示当前位置向右延伸的最长位置 + 1
    for(int i = 2; i < cnt ; i++){
        if(i < right) dp[i] = min(dp[2 * pos - i], right - i);
        else dp[i] = 1;
        while(tmp[i - dp[i]] == tmp[i + dp[i]]) dp[i]++;
        if(i + dp[i] > right){
            right = i + dp[i];
            pos = i;
        }
        if(dp[i] > 3 && dp[i] > dp[index]){
            f = (i - dp[i] + 2) / 2;
            e = (i + dp[i] - 2) / 2;
            ///这个自己画一下图就知道为什么了,这也就是为什么我把tmp数组从下标1开始记录#且s数组也是从下标1开始
            index = i;
        }
    }
    if(f < 0 || e < 0) {printf("No solution!\n"); continue;}
    printf("%d %d\n", f - 1, e - 1);
    for(int i = f; i <= e; i++){
        printf("%c", change(s[i], a[0]));
    }
    putchar('\n');
    }
    return 0;
}