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\n",ans);
90 }
posted @ 2019-02-23 14:54  Refun  阅读(227)  评论(0编辑  收藏  举报