• 洛谷 P3805【模板】manacher算法


    题目链接:https://www.luogu.com.cn/problem/P3805

    Manacher算法$O(n)$:

    求以每个字符为中心的最长回文串的半径:
    如果要求可以以字符间隙为回文中心,就要在每两个字符之间加入一个’#’,在开头加上'$',然后再解决。

    $pos$表示回文字串的对称轴,$mx$表示回文串在最右右边界,很明显$2 imes pos-i$即为$i$关于$pos$的对称点。

    令$r_i$为以$i$为中心的最长回文半径。从左往右依次求$r$数组:
    若$i>mx$,即$i$不在所已知的回文串的范围内,那么就让$r_i$从$1$开始计算。

    若$ileq mx$:

      设$j$为$i$关于$pos$的对称点,即$j=(2 imes pos-i)$。

      1),若$r_j>mx-i$,那么不能保证在mx右边仍为回文,所以这时$r_i=mx-i$。

      2),若$r_jleq mx-i$,那么根据对称性可以直接得到,$r_i=r_j$。

      综上所述,$r_i=min(r_j,mx-i)$。

    然后开始暴力往两边扩展,看看是否满足回文。如果右端点扩展到mx右边,则需要更新$mx$和$pos$。

    最后不难发现,$r_i-1$中的最大值即为答案,即$ans=max(ans,r_i-1)$。

    AC代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cstring>
     5 using namespace std;
     6 const int maxn=51000050;
     7 char str[maxn],s[maxn];
     8 int r[maxn];
     9 
    10 int manacher(int len){
    11     int t=0,ans=0;
    12     s[0]='$';s[++t]='#';
    13     for(int i=1;i<=len;i++){
    14         s[++t]=str[i];
    15         s[++t]='#';
    16     }
    17     int pos=0,mx=0;
    18     for(int i=1;i<=t;i++){
    19         if(i>mx) r[i]=1;
    20         else r[i]=min(r[2*pos-i],mx-i);
    21         while(i-r[i]>=1&&i+r[i]<=t&&s[i+r[i]]==s[i-r[i]]) r[i]++;
    22         if(i+r[i]>mx){
    23             mx=i+r[i];
    24             pos=i;
    25         }
    26         ans=max(ans,r[i]-1);
    27     }
    28     return ans;
    29 }
    30 
    31 int main(){
    32     scanf("%s",str+1);
    33     printf("%d
    ",manacher(strlen(str+1)));
    34     return 0;
    35 }
    AC代码
  • 相关阅读:
    Linux系统备份与还原
    今后的日程安排(面试期间)
    我的下一份工作是什么样子呢?
    WebView 放大缩小
    Android EditText赋值后光标在后面
    android中捕捉menu按键的点击事件
    Android控件常用属性
    点击autocompletetextview时,如果没有输入时显示默认列表
    在Activity里怎样获得另一个xml布局文件的控件
    Android中的AutoCompleteTextView的使用
  • 原文地址:https://www.cnblogs.com/New-ljx/p/12319190.html
Copyright © 2020-2023  润新知