题意:
判断是否能将字符串S分成三段非空回文串。
思路:
先预处理出前缀回文串和后缀回文串的位置,将位置分别装入两个集合中,O(n)。
针对每个前缀回文串的终点位置,挑出不相交的后缀回文串,对中间那段进行暴力匹配即可。只有20个case,不会超时的。
具体的算法参考HIHOCODER HIHO一下 第一周 #1032 : 最长回文子串 (特殊处理)
//#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
#include <set>
#include <string>
#include <iostream>
#include <deque>
#include <vector>
#define INF 0x7f7f7f7f
#define pii pair<int,int>
#define LL unsigned long long
using namespace std;
const int N=;
int len; //原串长
char str[N*]; //接收原来的串
char s[N*];
int P[N*]; //保存关于长度的信息(回文长度的一半再加1)
vector<int> vect[];
int cal(int q)
{
int id=, mx=, max1=;
P[]=;
P[]=;
for(int i=; s[i]!='\0'; i++) //考虑以i为中心的回文串
{
P[i] =i>mx? : min( P[*id-i],mx-i);
while(s[i+P[i]]==s[i-P[i]]) //在这比对
{
if(i-P[i]==) vect[q].push_back(i+P[i]); //已经匹配
P[i]++;
} if(i+P[i]>mx) //更新id和mx的位置
{
id=i;
mx=i+P[i];
}
if(P[i]->max1) //更新最大值
max1=P[i]-;
}
return max1;
} bool ok()
{
len=strlen(str);
sort(vect[].begin(), vect[].end());
sort(vect[].begin(), vect[].end()); for(int i=; i<vect[].size(); i++)//这里虽然穷举了所有可能,但通常都很少
{
for(int j=; j<vect[].size(); j++)
{
int l=vect[][i]+;
int r=len-vect[][j]-;
if(l>r) break; while( l<r && str[l]==str[r] )
l++,r--;
if(l==r && str[l]==str[r])
return true; }
}
return false;
} int main()
{
//freopen("input.txt", "r", stdin);
int t;
cin>>t;
while(t--)
{
scanf("%s",str);
len=strlen(str);
vect[].clear();
vect[].clear();
if(len==)///特别处理
{
puts("YES");
continue;
} s[]='$';
s[]='#';
int i=, j=;
for(; i<len; i++)
{
s[j++]=str[i];
s[j++]='#';
}
s[j]='\0';
strcpy(str,s);//先copy出一份拷贝
memset(P, , sizeof(P));
cal(); reverse(s,s+*len+);//反置过来,求后缀回文
s[]='$';
s[*len+]='\0';
memset(P, , sizeof(P));
cal(); if(ok())puts("Yes");
else puts("No");
}
return ;
}
AC代码