BZOJ 2342 [Shoi2011]双倍回文(Manacher)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2342

题意:求最长子串使得它有四个相同的回文串SSSS相连组成。

首先跑一边Manacher,初始化出以每一个点为最长回文串的左端点,然后按左端点排序。

枚举中间点$x$,然后找右面的中间点$y$,使得$y$满足

$y-p_yleq x$ 

$yleq x+r_xdiv 2$

用set维护y,然后求出最接近$x+r_xdiv 2$,用--upper_bound()返回$y$的迭代器it。(注意不要直接用lower_bound()

则$ans=max((*it)-i) imes 2$   -->因为有‘#’,*2即可。

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<set>
 6 using namespace std;
 7 const int N=500050;
 8 int p[N*2];
 9 char str[N],s[N*2];
10 int n,t,ans;
11 set<int> Set;
12 set<int>::iterator it;
13 
14 struct node{
15     int v,id;
16 }a[N];
17 
18 bool cmp(node x,node y){
19     return x.v<y.v;
20 }
21 
22 void manacher(int len){
23     s[0]='$'; s[++t]='#';
24     for(int i=1;i<=len;i++){
25         s[++t]=str[i];
26         s[++t]='#';
27     }
28     int pos=0,mx=0;
29     for(int i=1;i<=t;i++){
30         if(i>mx) p[i]=1;
31         else p[i]=min(p[2*pos-i],mx-i);
32         while(i+p[i]<=t&&i-p[i]>=1&&s[i+p[i]]==s[i-p[i]]) p[i]++;
33         if(i+p[i]>mx){
34             mx=i+p[i];
35             pos=i;
36         }
37     }
38 }
39 
40 void solve(){
41     int q=0;
42     for(int i=1;i<=t;i++) if(i&1) a[++q].v=i-p[i],a[q].id=i;
43     sort(a+1,a+q+1,cmp);
44     int now=1;
45     for(int i=1;i<=t;i++) if(i&1){
46         while(now<q&&a[now].v<=i) Set.insert(a[now].id),now++;
47         it=--Set.upper_bound(i+p[i]/2);
48         if(it!=Set.begin()) ans=max(ans,(*it)-i);
49     }
50     printf("%d
",ans*2);
51 }
52 
53 int main(){
54     scanf("%d",&n);
55     scanf("%s",str+1);
56     manacher(n);
57     solve();
58     return 0;
59 }
AC代码
原文地址:https://www.cnblogs.com/New-ljx/p/12344366.html