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

    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。

    Solution

    垃圾题目卡$SAM+Manacher$做法的空间……害我把所有的结构体全拆开还把$SAM$的$son$数组换成了$map$才过……

    首先众所周知,一个串的本质不同的回文子串只有$O(n)$级别,且在$Manacher$过程中右端点右移的情况就是本质不同的回文子串。所以我们可以做一遍$Manacher$把本质不同的回文子串求出来。

    假设现在的一个回文子串是$S_{l,r}$,设$SAM$插入$r$的时候的$np$节点为$node_r$,那么我们知道,$S_{l,r}$一定是$node_r$代表的子串的一个后缀,且$S_{l,r}$的出现次数是$right_{node_r}$。

    我们可以倍增从$node_r$往上跳,因为越往上跳$right$越大。跳到长度取值范围包括$r-l+1$的节点然后更新答案就可以了。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<map>
     5 #define N (600009)
     6 #define LL long long
     7 using namespace std;
     8 
     9 int to[N],nxt[N];
    10 int n,m,pos[N],len[N];
    11 int Depth[N],f[N][20];
    12 int head[N],num_edge;
    13 int p,q,np,nq,last=1,cnt=1;
    14 int fa[N],rig[N],step[N],node[N];
    15 map<int,int>son[N];
    16 LL ans;
    17 char s[N>>1],t[N];
    18 
    19 void add(int u,int v)
    20 {
    21     to[++num_edge]=v;
    22     nxt[num_edge]=head[u];
    23     head[u]=num_edge;
    24 }
    25 
    26 void Insert(int x)
    27 {
    28     p=last; np=last=++cnt; step[np]=step[p]+1; rig[np]=1;
    29     while (!son[p][x] && p) son[p][x]=np, p=fa[p];
    30     if (!p) fa[np]=1;
    31     else
    32     {
    33         q=son[p][x];
    34         if (step[q]==step[p]+1) fa[np]=q;
    35         else
    36         {
    37             nq=++cnt; step[nq]=step[p]+1;
    38             son[nq]=son[q];
    39             fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    40             while (son[p][x]==q) son[p][x]=nq, p=fa[p];
    41         }
    42     }
    43 }
    44 
    45 void DFS(int x,int fa)
    46 {
    47     Depth[x]=Depth[fa]+1; f[x][0]=fa;
    48     for (int i=1; i<=19; ++i) f[x][i]=f[f[x][i-1]][i-1];
    49     for (int i=head[x]; i; i=nxt[i])
    50         DFS(to[i],x), rig[x]+=rig[to[i]];
    51 }
    52 
    53 void Calc()
    54 {
    55     for (int i=0; i<n; ++i) Insert(s[i]-'a'), node[i]=np;
    56     for (int i=2; i<=cnt; ++i) add(fa[i],i);
    57     DFS(1,0);
    58 }
    59 
    60 void Solve(int p,int k)
    61 {
    62     while (t[p+k]=='#' || t[p+k]==')') --k;
    63     int x=node[pos[p+k]],y=pos[p+k]-pos[p-k]+1;
    64     for (int i=19; i>=0; --i) if (step[f[x][i]]>=y) x=f[x][i];
    65     ans=max(ans,1ll*rig[x]*y);
    66 }
    67 
    68 void Manacher()
    69 {
    70     t[++m]='(';
    71     for (int i=0; i<n; ++i) t[++m]='#', t[++m]=s[i], pos[m]=i;
    72     t[++m]='#'; t[++m]=')';
    73 
    74     int x,mid=0,maxn=0;
    75     for (int i=1; i<=m; ++i)
    76     {
    77         if (i>maxn) x=1;
    78         else x=min(maxn-i+1,len[mid*2-i]);
    79         while (t[i+x]==t[i-x]) Solve(i,x), ++x;
    80         len[i]=x;
    81         if (i+x-1>maxn) maxn=i+x-1, mid=i;
    82     }
    83 }
    84 
    85 int main()
    86 {
    87     scanf("%s",s); n=strlen(s);
    88     Calc(); Manacher();
    89     printf("%lld
    ",ans);
    90 }
  • 相关阅读:
    爬虫案例
    伪静态
    HTTP0.9、HTTP1.0、HTTP1.1、HTTP2的区别
    正向代理和反向代理
    数据结构继承
    APP 爬虫
    算法基础
    matplotlib
    Java类加载机制及自定义加载器
    SpringBoot war包部署到Tomcat服务器
  • 原文地址:https://www.cnblogs.com/refun/p/10422699.html
Copyright © 2011-2022 走看看