BZOJ 2342: [Shoi2011]双倍回文 [Manacher + set]
题意:
求最长子串使得它有四个相同的回文串SSSS相连组成
枚举中间x
找右边的中间y满足 y-r[y]<=x y<=x+r[x]/2
用个set维护
注意中间只能是#
#include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; const int N=1e6+5; typedef long long ll; int n; char s[N],str[N]; int r[N]; void Manacher(char s[],int n){ int p=0,a; for(int i=1;i<=n;i++){ r[i]=i<p?min(p-i+1,r[2*a-i]):1; while(s[i-r[i]]==s[i+r[i]]) r[i]++; if(i+r[i]-1>p) p=i+r[i]-1,a=i; } } void iniStr(char str[],char s[]){ for(int i=1;i<=n;i++) s[(i<<1)-1]='#',s[i<<1]=str[i]; s[n<<1|1]='#'; s[0]='@';s[(n<<1)+2]='$'; } set<int> Set; set<int>::iterator it; struct data{ int v,id; bool operator <(const data a)const{return v<a.v;} }a[N]; int ans; void solve(){ n=n<<1|1; int p=0; for(int i=1;i<=n;i++) if(i&1) a[++p].v=i-r[i],a[p].id=i; sort(a+1,a+1+p); int now=1; for(int i=1;i<=n;i++) if(i&1){ while(now<p&&a[now].v<=i) Set.insert(a[now].id),now++; it=--Set.upper_bound(i+r[i]/2); if(it!=Set.begin()) ans=max(ans,(*it)-i); } printf("%d",ans*2); } int main(){ freopen("in","r",stdin); scanf("%d%s",&n,str+1); iniStr(str,s); Manacher(s,n<<1|1); solve(); }
Copyright:http://www.cnblogs.com/candy99/