好好的马拉车不用,非要用回文树,结果调了半天
枚举回文中心位置,看这个位置的回文串是否可以和前缀或后缀接上,如果能接上,算答案的时候要优先取前后缀,即可能会截掉一部分回文串的两侧
用马拉车在s_new上非常方便处理
#include<bits/stdc++.h> using namespace std; #define N 2000005 char s[N],s_new[N]; int init(){ int len=strlen(s); int j=2; s_new[0]='$',s_new[1]='#'; for(int i=0;i<len;i++) s_new[j++]=s[i],s_new[j++]='#'; s_new[j]=0; return j; } int start,p[N],n; int manacher(){ int len=init(); int mx=0,id; start=0; for(int i=0;i<len;i++){ if(mx>i)p[i]=min(p[id*2-i],mx-i); else p[i]=1; while(s_new[i-p[i]]==s_new[i+p[i]])p[i]++; if(mx<i+p[i]) mx=i+p[i],id=i; } } int lens[N],POS; int main(){ int t;cin>>t; while(t--){ cin>>s; n=strlen(s); manacher(); for(int i=1;i<=n*2+1;i++) lens[i]=p[i]; n=n*2+1; POS=0; for(int i=1;i<=(n+1)/2;i++) if(s_new[i]==s_new[n-i+1])POS=i; else break; int Max=POS*2,pos1=POS,pos2=n-POS+1,flag=0; for(int i=POS+1;i<=n-POS;i++){ int pre=i-lens[i]; int suf=i+lens[i]; if(pre>POS && suf<n-POS+1)continue; if(POS-pre>=suf-(n-POS+1)){ pre=POS+1; suf=2*i-pre; if(Max<2*POS+suf-pre+1){ Max=2*POS+suf-pre+1; pos1=suf;pos2=n-POS+1; } }else{ suf=n-POS; pre=2*i-suf; if(Max<2*POS+suf-pre+1){ Max=2*POS+suf-pre+1; pos1=POS;pos2=pre; } } } if(pos1>=pos2)flag=1; if(flag){ cout<<s<<' '; }else { for(int i=1;i<=pos1;i++) if(s_new[i]!='#')cout<<s_new[i]; for(int i=pos2;i<=n;i++) if(s_new[i]!='#')cout<<s_new[i]; puts(""); } } } /* #a#c#b#b#a# */