题意:
给出一个字符串,能否分成三个非空回文串。
解析:
我们可以发现第一个串和第三个串,一定是最大回文串的某个串,那么Manacher 求出所有最大回文串的长度。
那么问题变成了求一个i和d 使得1<=d<=r(i)且pre[i−d]和suf[i+d]为真。枚举i,实际上就是问pre[i−r(i)..i−1]和suf[i+1..i+r(i)]取反后 这两段有没有一个位置两者均为1,暴力压位即可。
总时间复杂度为O(N2/32)。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20005;
char str[N<<1], s[N];
int p[N<<1], len, len2;
void manacher() {
len = strlen(s);
for(int i = 0; i < len; i++) {
str[i*2] = '#';
str[i*2+1] = s[i];
}
str[len*2] = '#';
str[len*2+1] = '\0';
len = strlen(str);
int maxp = 0, id = 0;
for(int i = 0; i < len; i++) {
if(maxp > i) p[i] = min(maxp-i, p[id*2-i]);
else p[i] = 1;
for(;str[i-p[i]] == str[i+p[i]] && i+p[i] < len && i-p[i] >= 0; p[i]++);
if(i+p[i] > maxp) {
maxp = p[i]+i;
id = i;
}
}
}
bool pre[40005], suf[40005];
int judge() {
len = strlen(s);
len2 = len * 2;
memset(pre, false, sizeof(bool)*len2);
memset(suf, false, sizeof(bool)*len2);
if (len == 3) return 1;
if (len < 3) return 0;
for (int i = 1; i <= len2; i++) {
if (p[i] - 1 == i)
pre[i + (p[i] - 1)] = true;
if (p[len2 - i] - 1 == i)
suf[len2 - i - (p[len2 - i] - 1)] = true;
}
for (int i = 1; i <= len2; i++) {
for (int j = 1; j < p[i]; j++) {
if (pre[i - j] && suf[i + j]) {
return 1;
}
}
}
return 0;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%s", s);
memset(p, 0, sizeof(p));
manacher();
if (judge()) printf("Yes\n");
else printf("No\n");
}
return 0;
}
本文介绍了一种算法,用于判断给定字符串是否可以被分为三个非空回文串。通过使用Manacher算法求解最大回文串长度,进一步通过枚举和位操作解决具体问题。
399

被折叠的 条评论
为什么被折叠?



