• Manacher || BZOJ 2342: [Shoi2011]双倍回文 || Luogu P4287 [SHOI2011]双倍回文


    题面:[SHOI2011]双倍回文

    题解:具体实现时,就是在更新mr时维护前半段是回文串的最长回文串就好了

    正确性的话,因为到i时如果i+RL[i]-1<=mr,那么答案肯定在i之前就维护过了;

    因此只有在i+RL[i]-1>mr时需要维护答案

    由于mr最多被更新N<<1次,所以时间效率是对的;在找前半段最长的回文串时,记得从外向内枚举,一旦发现答案就立即break,否则效率会假

    最后,注意只需要判前半段是否满足条件就好了,一是因为我们不清楚后半段相应位置的真实RL值,二是这是个回文串,左右是相等的。

    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define max(a,b) ((a)>(b)?(a):(b))
     5 #define min(a,b) ((a)<(b)?(a):(b))
     6 using namespace std;
     7 const int maxn=(5e5)+50;
     8 int N,len,mid,mr,RL[maxn<<1],ans=0,a;
     9 char O[maxn],S[maxn<<1];
    10 inline void Manacher(){
    11     mid=mr=0;
    12     for(int i=1;i<=len;i++){
    13         if(i<mr)RL[i]=min(mr-i,RL[(mid<<1)-i]);
    14         else RL[i]=1;
    15         while(S[i-RL[i]]==S[i+RL[i]])RL[i]++;
    16         if(i+RL[i]-1>mr){
    17             mr=i+RL[i]-1;
    18             mid=i;
    19             if(S[i]=='#'){
    20                 for(int j=RL[i]-1;j>=2;j-=2){
    21                     a=i-(j>>1);
    22                     if(a>=1&&S[a]=='#'&&a+RL[a]-1>=i){
    23                         ans=max(ans,j);
    24                         break;
    25                     }
    26                 }
    27             }
    28         }
    29     }
    30     return;
    31 }
    32 int main(){
    33     scanf("%d",&N);
    34     scanf("%s",O);
    35     S[0]='$';
    36     S[len=1]='#';
    37     for(int i=0;i<N;i++){
    38         S[++len]=O[i];
    39         S[++len]='#';
    40     }
    41     Manacher();
    42     printf("%d
    ",ans);
    43     return 0;
    44 }

    By:AlenaNuna

  • 相关阅读:
    软件工程15 结对编程作业
    软工网络15个人阅读作业2——提问题
    软件工程网络15个人阅读作业1
    第15周-反射与JSP
    Java课程设计-定时器(团队)
    Java课程设计-定时器
    第14周-数据库
    网络15软工个人作业5——软件工程总结
    软工网络15个人作业4——alpha阶段个人总结
    软工网络15个人作业3——案例分析
  • 原文地址:https://www.cnblogs.com/AlenaNuna/p/10901807.html
Copyright © 2020-2023  润新知