BZOJ2565: 最长双回文串
Description
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
Sample Input
baacaabbacabb
Sample Output
12
你考虑维护一个ex1数组,一个ex2数组。
ex1表示往左扩展最长的回文串。
ex2则反之。
#include <cstdio>
#include <cstring>
using namespace std;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
char ss[110000], now[210000];
int len, p[210000], ex1[110000], ex2[110000];
void manacher() {
int pos = 0, R = 0;
for(int i = 1; i <= len; i++) {
int j = 2 * pos - i;
if(i <= R) p[i] = _min(p[j], R - i);
else p[i] = 1;
while(1 <= i - p[i] && i + p[i] <= len && now[i - p[i]] == now[i + p[i]]) p[i]++;
if(i + p[i] - 1 > R) pos = i, R = i + p[i] - 1;
}
}
int main() {
scanf("%s", ss + 1);
len =strlen(ss + 1);
for(int i = 1; i <= len ; i++) {
now[i * 2 - 1] = '#';
now[i * 2] = ss[i];
}
len = len * 2 + 1;
now[len] = '#';
manacher();
int ans = 0;
for(int i = 1; i <= len / 2; i++) ex1[i] = ex2[i] = 1;
for(int i = 1; i <= len; i++) {
ex1[(i - p[i] + 2) / 2] = _max(ex1[(i - p[i] + 2) / 2], p[i] - 1);
ex2[(i + p[i] - 1) / 2] = _max(ex2[(i + p[i] - 1) / 2], p[i] - 1);
}
for(int i = 1; i <= len / 2; i++) ex1[i] = _max(ex1[i], ex1[i - 1] - 2);
for(int i = len / 2; i >= 1; i--) ex2[i] = _max(ex2[i], ex2[i + 1] - 2);
for(int i = 2; i <= len / 2; i++) ans = _max(ans, ex2[i - 1] + ex1[i]);
printf("%d\n", ans);
return 0;
}
[Shoi2011]双倍回文
Description
给出一个字符串,求出一个最长的子串满足不但由两个回文子串组成,而且本身也是一个回文串,且这两个回文子串不重叠,并且这两个回文子串长度为偶数,也就是说原子串的长度一定是4的倍数
Sample Input
16
ggabaabaabaaball
Sample Output
12
你枚举一个回文中心。
然后你设这个回文中心扩展最多到s。
你从s/2那个位置开始枚举,遇到合适的就break。
这样其实是不能出数据卡的。。。
#include <cstdio>
#include <cstring>
using namespace std;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
char ss[510000], now[1100000];
int len, p[1100000];
void manacher() {
int pos = 0, R = 0;
for(int i = 1; i <= len; i++) {
int j = 2 * pos - i;
if(i <= R) p[i] = _min(p[j], R - i);
else p[i] = 1;
while(1 <= i - p[i] && i + p[i] <= len && now[i - p[i]] == now[i + p[i]]) p[i]++;
if(i + p[i] - 1 > R) pos = i, R = i + p[i] - 1;
}
}
int main() {
scanf("%d", &len);
scanf("%s", ss + 1);
for(int i = 1; i <= len ; i++) {
now[i * 2 - 1] = '#';
now[i * 2] = ss[i];
}
len = len * 2 + 1;
now[len] = '#';
manacher();
int ans = 0;
for(int i = 3; i < len; i += 2) {
int uu = i - p[i] / 2;
if(uu % 2 == 0) uu++;
for(int j = uu; j < i - 2; j += 2) {
if(j + p[j] - 1 >= i) {
ans = _max(ans, (i - j) * 2);
break;
}
}
}
printf("%d\n", ans);
return 0;
}