• P3649 [APIO2014]回文串


    题目描述

    给你一个由小写拉丁字母组成的字符串 ss。我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这个子串的长度。

    对于给你的这个字符串 ss,求所有回文子串中的最大存在值。

    输入格式

    一行,一个由小写拉丁字母(a~z)组成的非空字符串 ss。

    输出格式

    输出一个整数,表示所有回文子串中的最大存在值。

    输入输出样例

    输入 #1
    abacaba
    
    输出 #1
    7
    
    输入 #2
    www
    输出 #2
    4

    说明/提示

    【样例解释1】

    用 lvert s verts∣ 表示字符串 ss 的长度。

    一个字符串 s_1 s_2 dots s_{lvert s vert}s1s2ss 的子串是一个非空字符串 s_i s_{i+1} dots s_jsisi+1sj,其中 1 leq i leq j leq lvert s vert1ijs∣。每个字符串都是自己的子串。

    一个字符串被称作回文串当且仅当这个字符串从左往右读和从右往左读都是相同的。

    这个样例中,有 77 个回文子串 a,b,c,aba,aca,bacab,abacaba。他们的存在值分别为 4, 2, 1, 6, 3, 5, 74,2,1,6,3,5,7。

    所以回文子串中最大的存在值为 77。

    第一个子任务共 8 分,满足 1 leq lvert s vert leq 1001s100。

    第二个子任务共 15 分,满足 1 leq lvert s vert leq 10001s1000。

    第三个子任务共 24 分,满足 1 leq lvert s vert leq 100001s10000。

    第四个子任务共 26 分,满足 1 leq lvert s vert leq 1000001s100000。

    第五个子任务共 27 分,满足 1 leq lvert s vert leq 3000001s300000。

    题解

    首先建立$SAM$的时候存储一下字符串上的每一位对应$SAM$上的哪个节点(也就是将串首到这一位放到$SAM$上跑会跑到哪个节点)

    再用倍增处理一下$parent$树(每个节点的$father$都是与当前子串$right$集合不等价,且是当前子串的最长后缀)

    然后跑$manacher$,对于$manacher$过程中的每个回文中心$i$,在 扩展这个回文中心的半径$r$的时候,每扩展一次,就可以得到一个合法的回文串$S=(i-r+1,i+r-1)$

    如何快速找出回文串的出现次数呢?我们前面存了字符串的每一位对应$SAM$上的哪个点,设这个点为$pos$,那我们就可以得到$pos$代表的子串$(?,i+r-1)$,且这个子串包含回文串$S$。

    然后从$pos$点开始重复往$father$节点跳,每跳一次可以得到当前子串的一个后缀,直到跳到这个后缀是$S=(i-r+1,i+r-1)$为止。这个跳父亲节点的操作可以用倍增优化。

    代码

     1 #include<bits/stdc++.h>
     2 #define N (600009)
     3 #define LL long long
     4 using namespace std;
     5 
     6 int f[N][15],len[N],fir[N],n;
     7 LL ans;
     8 char a[N],s[N];
     9 
    10 struct SAM {
    11     int p,q,np,nq,last,cnt;
    12     int son[N][26],fa[N],step[N],right[N],pos[N];
    13     int wt[N],od[N];
    14     SAM() {last=++cnt;}
    15     
    16     void Insert(int x,int id) {
    17         p=last; np=last=++cnt; step[np]=step[p]+1; right[np]=1; pos[id]=np;
    18         while(!son[p][x] && p) son[p][x]=np, p=fa[p];
    19         if (!p) fa[np]=1;
    20         else {
    21             q=son[p][x];
    22             if (step[q]==step[p]+1) fa[np]=q;
    23             else {
    24                 nq=++cnt; step[nq]=step[p]+1;
    25                 memcpy(son[nq],son[q],sizeof(son[q]));
    26                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    27                 while (son[p][x]==q) son[p][x]=nq, p=fa[p];
    28             }
    29         }
    30     }
    31     void Init() {
    32         int len=strlen(a);
    33         for (int i=1; i<=cnt; ++i) wt[step[i]]++;
    34         for (int i=1; i<=len; ++i) wt[i]+=wt[i-1];
    35         for (int i=cnt; i>=1; --i) od[wt[step[i]]--]=i;
    36         for (int i=cnt; i>=1; --i) right[fa[od[i]]]+=right[od[i]];
    37         
    38         for (int i=1; i<=cnt; ++i) {
    39             f[i][0]=fa[i];
    40             for (int j=1; j<=14; ++j) f[i][j]=f[f[i][j-1]][j-1];
    41         }
    42     }
    43     
    44     void Check(int l,int r) {
    45         if (l<1 || r>n) return;
    46         int now=pos[r];
    47         for (int i=14; i>=0; --i) {
    48             if (step[f[now][i]]>=r-l+1) now=f[now][i];
    49         ans=max(ans,1ll*right[now]*(r-l+1));
    50     }
    51 }
    52 }SAM;
    53 
    54 void Manacher() {
    55     int tot=0;
    56     s[++tot]='@'; s[++tot]='#';
    57     for (int i=0; i<n; ++i) s[++tot]=a[i], fir[tot]=i+1, s[++tot]='#';
    58     s[++tot]='$';
    59     
    60     int x,ans=0,mid=0,maxn=0;
    61     for (int i=1; i<=tot; ++i) {
    62         if (i>maxn) x=1;
    63         else x=min(maxn-i+1,len[mid*2-i]);
    64         SAM.Check(fir[i-x+1],fir[i+x-1]);
    65         while (s[i+x]==s[i-x]) ++x, SAM.Check(fir[i-x+1],fir[i+x-1]);
    66         len[i]=x;
    67         if (i+x-1>maxn) maxn=i+x-1, mid=i;
    68     }
    69 }
    70 
    71 int main() {
    72     cin>>a;
    73     n=strlen(a);
    74     for (int i=1; i<=n; ++i) SAM.Insert(a[i-1]-'a',i);
    75     SAM.Init(); 
    76     Manacher();
    77     cout<<ans<<endl;
    78 }
  • 相关阅读:
    窗口和消息
    输出文字
    《windows程序设计》第一章,建议想学API的每天看一章
    hdu 1008为何不对?求大神指导!
    课程设计(物体类),图片可能没有加载出来,自己运行一下就行了
    二叉树前序、中序、后序遍历相互求法
    哈希表工作原理
    c++中关于static关键字的问题
    Halcon学习笔记之缺陷检测(二)
    Halcon学习笔记之缺陷检测(一)
  • 原文地址:https://www.cnblogs.com/refun/p/15026846.html
Copyright © 2020-2023  润新知