啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊我好激动啊!!!!!
我竟然A了!!!!!
好吧,其实这是一道模板题。(要用manacher来做(其实我觉得这算法名挺好记))
首先,我们发现回文串的长度有奇偶性,为了方便计算,我们在原串上每两个字符中间添加一个另外的字符,使原串变为奇数串。我们又发现,由于这道题玄学的 数据,0号位和n*2+2号位必须有其他的乱七八糟的值(不然会多算)。
先上马吧!
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int h = 1202;
struct node {
string ch[h];
int cnt;
}ans[h];
char s[h];
int n, len[h << 1], t[h << 1];
string tmp;
void init() {
for(int i = 1; i <= n * 2 + 1; i ++)
t[i] = '#';
t[0] = '@';
t[n * 2 + 2] = '$';
for(int i = 1; i <= n; i ++)
t[i << 1] = s[i - 1];
}
void manacher() {
init();
int mid = -1, r = -1;
n <<= 1;
n ++;
len[0] = (1 << 30) - 1;
for(int i = 1; i <= n; i ++) {
len[i] = (i <= r) ? min(r - i + 1, len[mid * 2 - i]) : 1;
if(t[i - len[i] + 1] == '#' && len[i] > 2 && t[i - len[i] + 1] == t[i + len[i] - 1]) {
ans[len[i] - 2].cnt ++;
for(int j = i - len[i] + 1; j < i + len[i]; j ++)
if(t[j] != '#')
ans[len[i] - 2].ch[ans[len[i] - 2].cnt] += t[j];
}
while(t[i - len[i]] == t[i + len[i]]) {
if(len[i] >= 2 && t[i - len[i]] == '#') {
ans[len[i] - 1].cnt ++;
for(int j = i - len[i]; j <= i + len[i]; j ++)
if(t[j] != '#')
ans[len[i] - 1].ch[ans[len[i] - 1].cnt] += t[j];
}
len[i] ++;
}
if(i + len[i] - 1 >= r) {
r = i + len[i] - 1;
mid = i;
}
}
}
int main() {
cin.getline(s, h);
n = strlen(s);
manacher();
for(int i = 1; i <= 1200; i ++) {
if(ans[i].cnt == 0)
continue;
for(int j = 1; j <= ans[i].cnt; j ++)
cout << ans[i].ch[j] << endl;
}
return 0;
}
让我们好好研读这份代码:
mid表示以mid为中心向外延伸的字串,r表示中心为mid的最长回文串的右边界,len数组存储中心为i的最长回文串的半径(包含点i)。
继续看看这个递推式:
首先我们知道,i是一定严格大于mid的。所以如果i<r,len[mid * 2 - 1]一定等于len[i]。先别急着点头,如果len[mid * 2 - 1]所代表的回文串左边界超出了l(我们定义l为中心为mid的最长回文串的左边界),那么len[mid * 2 - 1]就不一定等于len[i]了。所以我们需要用另一个条件来限制:r-i+1即i与r的距离。
至于函数最后的赋值,大于等于和大于都没毛病。(请手推)
另外,我那清奇的码风得归功于一组数据:
111
ans:
11
11
111
好了,我已经心力交瘁了,拜拜!