题意:题目的意思已经描述的很详细了,这里只作简要的说明,就是存在这样的一个字符串,A+pre+B+middle+C+suffix,我们要求的就是pre+middle+suffix的最大值。
思路:最主要的思路就是枚举中缀的所有情况,用malacher算法求出以该节点的半径,那么middle就出来了,然后根据middle求pre+suffix,由于pre==suffix,类似于回文串的情况,但是中间存在有其他字符串干扰的情况出现,这情况类似于KMP算法中的next数组的特点,next数组是前面i个字符所能匹配的最长的子串的下标,所以我们需要求next数组,当时我们不能直接求,需要将原字符串赋值一份到后面,然后将前面的翻转(如:ABCD-->DCBA#ABCD)中间的#起分隔符作用,求出了next数字,我们从#后面的A开始枚举,枚举最长pre+middle+suffix的情况。
代码:
#include<bits\stdc++.h>
#define N 200020
using namespace std;
int n,ex[N], nextVal[N], len[N], id[N], f[N];//len保存的是前i个字符的匹配最长的下标;//ex保存的是以每个点的半径
char s[N], t[N];//s为原字符串,t为转化后的字符串
void manacher() {
int po = 0, mx = 0;//len数组马拉车算法辅助数组
for (int i = 1; i <= n; i++) {
if (mx > i) {
f[i] = min(f[2 * po - i], mx - i);
}
else {
f[i] = 1;
}
while (t[i - f[i]] == t[i + f[i]]) {
f[i]++;
}
if (i + f[i] > mx) {
mx = f[i]+i;
po = i;
}
}
for (int m = 0, i = 2; i < n; i+=2) {
ex[++m] = f[i] >> 1;
}
}
int main() {
int cnt = 0;
scanf("%s", s + 1);
int m = strlen(s + 1);
{//马拉车算法的准备
t[0] = '#';
for (int i = 1; i <= m; i++) {
t[++n] = '#';
t[++n] = s[i];
}
t[++n] = '#';
}
manacher();//执行马拉车算法
{//求nextVal数组的准备
s[m + 1] = '#';
for (int i = 1; i <= m; i++) {
s[m + 1 + i] = s[i];
}
reverse(s + 1, s + 1 + m);
}
{//求nextVal数组,变形的nextVal数组,因为-1被0代替
int j = -1;
for (int i = 2; i <= 2*m+1;i++) {
while ((j != 0) && s[j + 1] != s[i]) {
j = nextVal[j];
}
j += (s[j + 1] == s[i]);
nextVal[i] = j;
}
}
int maxlen = 0, mIndex = 0, mLen = 0, pIndex = 0, pLen = 0, sIndex = 0, sLen = 0;//maxlen前缀+中缀+后缀的最大情况
for (int i = 1; i <= m; i++) {
len[i] = len[i - 1];
id[i] = id[i - 1];
int tem = nextVal[m + 1 + i];
if (tem > len[i]) {
len[i] = tem;
id[i] = i;
}
int j = ex[i];//以i为中心的半径
int r = min(len[i - j], m - i - j + 1);
if (2 * r + 2 * j - 1 > maxlen) {
maxlen = 2 * r + 2 * j - 1;
mIndex = i - j + 1;
mLen = 2 * j - 1;
if (r != 0) {
pLen = sLen = r;//前后缀的长度
pIndex = id[i - j] - r + 1;//前缀的索引
sIndex = m - r + 1;//后缀的长度
}
else {
pLen = sLen = 0;
}
}
}
printf("%d\n", (pLen&&sLen) == 1 ? 3 : 1);//前缀与后缀的长度一样,故只有1和3的情况
if (pLen)printf("%d %d\n", pIndex, pLen);
printf("%d %d\n", mIndex, mLen);
if (sLen)printf("%d %d\n", sIndex, sLen);
return 0;
}