BZOJ 3676: [Apio2014]回文串 后缀自动机 Manacher 倍增

http://www.lydsy.com/JudgeOnline/problem.php?id=3676

过程很艰难了,第一次提交Manacher忘了更新p数组,超时,第二次是倍增的第0维直接在自动机里完成,但是忽略了增加新点时fa变动的情况,还是肉眼查错最管用。

得到的教训是既然倍增就在倍增的函数里完成,自动机就在自动机里完成,不要随便乱搞赋值。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<map>
 7 using namespace std;
 8 const int maxn=300010;
 9 char ch[maxn]={};
10 char ch1[maxn*2]={};
11 int siz,siz1;
12 struct sam{
13     int sig[26];
14     int f,len,d[21],num;
15 }t[maxn*2];
16 int tot=1,la=1;
17 int loc[maxn]={},cnt[maxn*2]={},b[maxn*2]={},p[maxn*2]={};
18 long long ans=0;
19 void add(int z){
20     int x=++tot,i=la;
21     t[x].len=t[la].len+1;
22     for(;i&&!t[i].sig[z];i=t[i].f)
23         t[i].sig[z]=x;
24     if(!i)t[x].f=1;
25     else{
26         int p=t[i].sig[z];
27         if(t[p].len==t[i].len+1)t[x].f=p;
28         else{
29             int y=++tot;
30             t[y]=t[p];t[y].len=t[i].len+1;
31             t[p].f=t[x].f=y;
32             for(;i&&t[i].sig[z]==p;i=t[i].f)
33                 t[i].sig[z]=y;
34         }
35     }
36     la=x;
37 }
38 void pre(){
39     int z;
40     for(int i=1;i<=tot;i++)cnt[t[i].len]++;
41     for(int i=1;i<=siz;i++)cnt[i]+=cnt[i-1];
42     for(int i=tot;i;i--)b[cnt[t[i].len]--]=i;
43     for(int i=1;i<=siz;i++)t[loc[i]].num=1;
44     for(int i=tot;i;i--){
45         z=b[i];t[t[z].f].num+=t[z].num;
46     }
47     for(int i=1;i<=tot;i++){
48         z=b[i];t[z].d[0]=t[z].f;
49         for(int j=1;j<=20;j++)
50             t[z].d[j]=t[t[z].d[j-1]].d[j-1];
51     }
52 }
53 void getit(int l,int r){
54     r=r/2;l=(l+1)/2;
55     if(r<l)return;
56     int z=loc[r];
57     for(int i=20;i>-1;i--){
58         if(t[t[z].d[i]].len>=r-l+1){
59             z=t[z].d[i];
60         }
61     }
62     long long sum=(long long)t[z].num*(r-l+1);
63     if(ans<sum)ans=sum;
64 }
65 void Manacher(){
66     for(int i=1;i<=siz;i++)ch1[i*2]=ch[i],ch1[i*2-1]=‘#‘;
67     ch1[siz*2+1]=‘#‘;ch1[siz*2+2]=‘\0‘;ch1[0]=‘$‘;
68     siz1=siz*2+1;
69     int mx=0,id=0;
70     for(int i=1;i<=siz1;i++){
71         if(mx>=i)p[i]=min(mx-i,p[id*2-i]);
72         else p[i]=0;
73         while(ch1[i+p[i]]==ch1[i-p[i]]){++p[i];getit(i-p[i]+1,i+p[i]-1);}
74         if(mx<i+p[i]){mx=i+p[i];id=i;}
75     }
76 }
77 int main(){
78     memset(t,0,sizeof(t));
79     scanf("%s",ch+1);siz=strlen(ch+1);
80     for(int i=1;i<=siz;i++){loc[i]=tot+1;add(ch[i]-‘a‘);}
81     pre();
82     Manacher();
83     printf("%lld\n",ans);
84     return 0;
85 }

原文地址:https://www.cnblogs.com/137shoebills/p/8572781.html

时间: 2024-08-27 18:58:22

BZOJ 3676: [Apio2014]回文串 后缀自动机 Manacher 倍增的相关文章

BZOJ 3676: [Apio2014]回文串 回文串自动机

裸的回文串自动机 3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 504  Solved: 152 [Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s

bzoj 3676: [Apio2014]回文串 回文自动机

3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 844  Solved: 331[Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,

字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串

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 一个串是回文的,当且仅当它从左

bzoj 3676: [Apio2014]回文串

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 一个串是回文的,当且

BZOJ 3676 [Apio2014]回文串(回文树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题目大意] 考虑一个只包含小写拉丁字母的字符串s. 我们定义s的一个子串t的"出现值"为t在s中的出现次数乘以t的长度. 求s的所有回文子串中的最大出现值. [题解] 我们对给出串建立回文树,统计每个回文串出现次数和长度,相乘取组大即可 [代码] #include <cstdio> #include <algorithm> #include

bzoj 3676 [Apio2014]回文串(Manacher+SAM)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题意] 给定一个字符串,定义一个串的权值为长度*出现次数,求最大权的回文子串. [思路] 马拉车求出本质不同的回文子串. 对于一个回文子串,在SAM中用倍增法在O(logn)的时间得到它的出现次数,即SAM中每个节点的right集大小,倍增数组和right都可以通过提前处理得到. 更新答案即可. [代码] 1 #include<set> 2 #include<cmat

【BZOJ】3676 [Apio2014]回文串

[算法]回文树 [题解]建回文数,然后一个回文子串出现的次数就是结点被访问的次数以及能包含它的结点被访问的次数. 根据fail树反向建新树,那么答案就是结点所在子树的权值和(权值就是结点被访问次数). #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=300010; char s[maxn]; int n,len,l,sz,first[ma

【BZOJ 3676】 [Apio2014]回文串

3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 646 Solved: 219 [Submit][Status][Discuss] Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出

hdu 3068 最长回文串 o(n) Manacher 算法

最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10596    Accepted Submission(s): 3759 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多