题意 : 给定一个长度小于20000的字符串, 问是否可以分割成3段非空回文字符串。
分析: manacher预处理出前缀和后缀回文的位置, 然后判断中间部分是否回文即可, 复杂度o(n2);
#include
using namespace std;
const int N = 20000 + 5;
int p[N << 1]; // 最长回文半径
char s[N], str[N << 1];
void prepare() {
int n = 0;
str[n ++] = '$';
for (int i = 0; s[i]; i ++) {
str[n ++] = '#';
str[n ++] = s[i];
}
str[n ++] = '#';
str[n] = 0;
}
bool work() {
int maxl = 0, index;
int len = strlen(str + 1);
// 求p[]
for (int i = 1; i <= len; i ++) {
if (maxl > i) {
p[i] = min(p[2 * index - i], maxl - i);
} else {
p[i] = 1;
}
while (str[i - p[i]] == str[i + p[i]]) {
p[i] ++;
}
if (p[i] + i > maxl) {
index = i;
maxl = p[i] + i;
}
}
vector
pre(0), suf(0);
for (int i = 1; i <= len; i ++) {
if (i - p[i] + 1 == 1 && i != 1) {
pre.push_back(i + p[i] - 1);
}
if (i + p[i] - 1 == len && i != len) {
suf.push_back(i - p[i] + 1);
}
}
for (int i = 0; i < pre.size(); i ++) {
for (int j = 0; j < suf.size(); j ++) if (pre[i] < suf[j]) {
int x = (pre[i] + 1 + suf[j] - 1) / 2;
if (2 * p[x] - 1 >= suf[j] - 1 - pre[i] - 1 + 1) {
return true;
}
}
}
return false;
}
int main() {
int t;
scanf("%d", &t);
while (t --) {
scanf("%s", s);
prepare();
puts(work() ? "Yes" : "No");
}
return 0;
}