zoukankan      html  css  js  c++  java
  • [BZOJ3676][APIO2014]回文串(Manacher+SAM)

    3676: [Apio2014]回文串 

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 3097  Solved: 1408
    [Submit][Status][Discuss]

    Description

    考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 
    现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最 
    大出现值。 

    Input

    输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。 

    Output


    输出一个整数,为逝查回文子串的最大出现值。 

    Sample Input

    【样例输入l】
    abacaba

    【样例输入2]
    www

    Sample Output

    【样例输出l】
    7

    【样例输出2]
    4

    HINT



    一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。 

    在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中: 

    ● a出现4次,其出现值为4:1:1=4 

    ● b出现2次,其出现值为2:1:1=2 

    ● c出现1次,其出现值为l:1:l=l 

    ● aba出现2次,其出现值为2:1:3=6 

    ● aca出现1次,其出现值为1=1:3=3 

    ●bacab出现1次,其出现值为1:1:5=5 

    ● abacaba出现1次,其出现值为1:1:7=7 

    故最大回文子串出现值为7。 

    【数据规模与评分】 

    数据满足1≤字符串长度≤300000。

    代码总用时:3h

    很简单的一道题,只要意识到Manacher算法的本质(本质不同的回文串的个数是O(n)的),配合后缀自动机或者后缀数组就可以轻松解决。

    但这道题调了好久,浪费了很多时间,一是因为后缀自动机模板不熟练,而是Manacher算法流程没有一个清楚的认识。

    写代码的时候精力要高度集中,不能因为低级错误耽误时间。

    下面是SAM版本的代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=600100;
     9 int cnt=1,lst=1,n,tot[N],mx[N],p[N],pos[N],son[N][27],fa[N],f[N][20],q[N],R[N];
    10 ll ans; char s[N],S[N];
    11 
    12 void ext(int c,int x){
    13     int p=lst,np=lst=++cnt; mx[np]=mx[p]+1; R[np]=1; pos[x]=np;
    14     while (!son[p][c] && p) son[p][c]=np,p=fa[p];
    15     if (!p) fa[np]=1;
    16     else{
    17         int q=son[p][c];
    18         if (mx[q]==mx[p]+1) fa[np]=q;
    19         else{
    20             int nq=++cnt; mx[nq]=mx[p]+1;
    21             memcpy(son[nq],son[q],sizeof(son[q]));
    22             fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    23             while (son[p][c]==q && p) son[p][c]=nq,p=fa[p];
    24         }
    25     }
    26 }
    27 
    28 void pre(){
    29     rep(i,1,cnt) tot[mx[i]]++;
    30     rep(i,1,n) tot[i]+=tot[i-1];
    31     for (int i=cnt; i; i--) q[tot[mx[i]]--]=i;
    32     for (int i=cnt; i; i--) R[fa[q[i]]]+=R[q[i]];
    33     rep(i,1,cnt){
    34         f[i][0]=fa[i];
    35         rep(j,1,19) f[i][j]=f[f[i][j-1]][j-1];
    36     }
    37 }
    38 
    39 void get(int l,int r){
    40     l=(l>>1)+(l&1); r>>=1; int x=pos[r];
    41     for (int i=19; ~i; i--)
    42         if (mx[f[x][i]]>=r-l+1) x=f[x][i];
    43     ans=max(ans,1ll*R[x]*(r-l+1));
    44 }
    45 
    46 void manacher(){
    47     int mxlen=0,id;
    48     rep(i,1,n){
    49         if (mxlen>i) p[i]=min(mxlen-i,p[2*id-i]);
    50             else{ p[i]=1; if (S[i]!='#') get(i,i); }
    51         while (S[i+p[i]]==S[i-p[i]]) get(i-p[i],i+p[i]),p[i]++;
    52         if (p[i]+i>mxlen) mxlen=p[i]+i,id=i;
    53     }
    54 }
    55 
    56 int main(){
    57     freopen("palindromes.in","r",stdin);
    58     freopen("palindromes.out","w",stdout);
    59     scanf("%s",s+1); n=strlen(s+1);
    60     rep(i,1,n) ext(s[i]-'a',i);
    61     pre(); S[0]='$'; S[1]='#';
    62     rep(i,1,n) S[(i<<1)+1]='#',S[i<<1]=s[i];
    63     n=(n<<1)+1; manacher(); printf("%lld
    ",ans);
    64     return 0;
    65 }
  • 相关阅读:
    重构的信号
    枚举类返回Map键值对,绑定到下拉框
    js onclick函数中传字符串参数的问题
    python opencv3 矩形 圆形边框
    python opencv3 轮廓检测
    python opencv3 滤波器 卷积核
    python opencv3 窗口显示摄像头的帧
    python opencv3 显示一张图片
    python opencv3 获取摄像头视频
    python opencv3 视频文件的读写
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8227465.html
Copyright © 2011-2022 走看看