题目链接:https://vjudge.net/problem/HDU-5340
题意:给定一个长度为n的字符串,问能不能将其分解成3个回文串。(n<=2e4)
思路:
先用Manacher算法得到以每个点为中心的最大回文串的左右边界le[i]、ri[i]。并且当le[i]==1(即该回文串向左可以到达字符串的边界)时,记录下来,le1[ri[i]]=1,表示存在一个回文串左边界为1,右边界为ri[i]。同理,当ri[i]==n-1(字符串右边界)时,ri1[le[i]]=1。
然后遍历中间的回文串的回文中心,令t1=p[i]-1(回文串长度),t2=le[i](回文串左边界),t3=ri[i](回文串右边界),当le1[t2]==1&&ri1[t3]==1时即找到了方案。如果不满足,t1-=2,t2+=2,t3-=2,继续判断,直到t1<=0。要注意的是当t2==1或者t3==n-1时该回文串不能作为中间回文串。
详见代码。
AC code:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=2e4+5; int T,n,ans,p[maxn<<1],le[maxn<<1],ri[maxn<<1]; int le1[maxn<<1],ri1[maxn<<1]; char s[maxn<<1],ss[maxn]; void manacher(){ int mid=0,r=0; for(int i=1;i<n;++i){ if(r>=i) p[i]=min(p[(mid<<1)-i],r-i+1); while(s[i-p[i]]==s[i+p[i]]) ++p[i]; if(i+p[i]>r) r=i+p[i]-1,mid=i; int tmp=p[i]-1; le[i]=i-tmp,ri[i]=i+tmp; if(le[i]==1) le1[ri[i]]=1; if(ri[i]==n-1) ri1[le[i]]=1; } } int main(){ scanf("%d",&T); while(T--){ scanf("%s",ss); ans=0; n=strlen(ss); s[0]='~',s[1]='|'; for(int i=0;i<n;++i) s[2*i+2]=ss[i],s[2*i+3]='|'; n=2*n+2; for(int i=0;i<n;++i) p[i]=0,le1[i]=0,ri1[i]=0; manacher(); for(int i=1;i<n;++i){ int t1=p[i]-1,t2=le[i],t3=ri[i]; if(t2==1||t3==n-1){ t1-=2; t2+=2; t3-=2; } while(t1>0){ if(le1[t2]&&ri1[t3]){ ans=1; break; } t1-=2; t2+=2; t3-=2; } if(ans) break; } if(ans) printf("Yes "); else printf("No "); } return 0; }