山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 2342 [Shoi2011]双倍回文(manacher,set)

 

【题目链接】

 

    http://www.lydsy.com/JudgeOnline/problem.php?id=2342

 

【题意】

 

    求出形如w wR w wR的最长连续子串。

 

【思路】

 

    用manacher算法计算出p[],表示以i与i+1为中心的最长回文字串长度/2

    枚举第一个wR的结束位置x,当且仅当y-p[y]<=x且y<=x+p[x]/2子串[x+1,y]是一个答案,更新ans。

    满足的条件是一个二维偏序,按照y-p[y]排序,在查询x之前保证将所有满足第一个式子的x'加入set,查询时找到x+p[x]/2在set中的前驱即为最大的答案。

 

【代码】

 

 1 #include<set>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 5e5+10;
 8 
 9 set<int> t;
10 set<int> ::iterator it;
11 
12 char s[N];
13 int n,ans,p[N],q[N];
14 
15 bool cmp(int a,int b)
16 {
17     return (a-p[a])<(b-p[b]);
18 }
19 
20 void manacher()
21 {
22     int mx=0,id;
23     for(int i=1;i<=n;i++)
24     {
25         if(mx>=i)p[i]=min(mx-i,p[2*id-i]);
26         else 
27             p[i]=0;
28         while(s[i+p[i]+1]==s[i-p[i]]) p[i]++;
29         if(p[i]+i>mx)id=i,mx=p[i]+i;
30     }
31 }
32 
33 int main()
34 {
35     scanf("%d%s",&n,s+1);
36     s[0]='#';
37     manacher();
38     for(int i=1;i<=n;i++) q[i]=i;
39     sort(q+1,q+n+1,cmp);
40     int now=1;
41     for(int i=1;i<=n;i++)
42     {
43         while(now<=n&&q[now]-p[q[now]]<=i)
44             t.insert(q[now++]);
45         it=t.upper_bound(i+p[i]/2);
46         if(it!=t.begin())
47             ans=max(ans,(*--it-i)*4);
48     }
49     printf("%d\n",ans);
50     return 0;
51 }

 

P.S. 新姿势[马拉车]解锁 :)

 

posted on 2016-04-02 23:46  hahalidaxin  阅读(513)  评论(0编辑  收藏  举报