BZOJ 3676 [Apio2014]回文串 (后缀自动机+manacher/回文自动机)
题目大意:
给你一个字符串,求其中回文子串的长度*出现次数的最大值
明明是PAM裸题我干嘛要用SAM做
回文子串有一个神奇的性质,一个字符串本质不同的回文子串个数是$O(n)$级别的
用$manacher$的思想分析一下,$maxright$指针向右扩展才会产生新的回文串
其它的回文串都根据之前求得的信息得到的,比如根据回文中心对称,或者是不超过当前最长回文上限
每次扩展成功时,都把这个回文串放到$SAM$里跑
预处理出每个前缀结尾在$SAM$里的节点编号,就不用每次都从头跑了
沿着$pre$指针倍增地往上跳,直到跳到当前节点能表示出这个回文串为止
注意长度为1的串的情况
如果被卡空间了,会发现预处理以后,trs指针没什么用了,把它当成倍增的数组吧
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 305000
#define S1 (N1<<1)
#define T1 (N1<<2)
#define ll long long
#define uint unsigned int
#define rint register int
#define dd double
#define il inline
#define inf 0x3f3f3f3f
#define idx(X) (X-'a')
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,m,len;
/*struct Edge{
int head[S1],to[S1],nxt[S1],cte;
void ae(int u,int v){
cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;}
}E;*/
namespace SAM{
int trs[S1][],pre[S1],dep[S1],ed[S1],pos[S1],la,tot;
void init(){tot=la=;}
void insert(int c,int id)
{
int p=la,np=++tot,q,nq;la=np;
dep[np]=dep[p]+;
pos[id]=np,ed[np]=;
for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np;
if(!p) {pre[np]=;return;}
q=trs[p][c];
if(dep[q]==dep[p]+) pre[np]=q;
else{
pre[nq=++tot]=pre[q];
pre[q]=pre[np]=nq;
dep[nq]=dep[p]+;
memcpy(trs[nq],trs[q],sizeof(trs[q]));
for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq;
}
}
int hs[S1],que[S1],sz[S1];
//int ff[S1][20];
void build()
{
int i,j,x;
for(i=;i<=tot;i++) hs[dep[i]]++;
for(i=;i<=n;i++) hs[i]+=hs[i-];
for(i=;i<=tot;i++) que[hs[dep[i]]--]=i;
for(i=tot;i;i--)
{
x=que[i];//E.ae(pre[x],x);
if(ed[x]) sz[x]++;
sz[pre[x]]+=sz[x];
trs[x][]=x,trs[x][]=pre[x];
}
for(j=;j<=;j++)
for(i=;i<=tot;i++)
trs[i][j]=trs[ trs[i][j-] ][j-];
}
int solve(int x,int s,int e)
{
int fx,L=e-s+;
for(int j=;j>=;j--)
//for(int j=5;j>=0;j--)
{
if(!trs[x][j]) continue;
fx=trs[x][j];
if(dep[fx]>=L) x=fx;
}
return sz[x];
}
};
char str[N1],man[S1];
int p[S1],hs[]; int main()
{
//freopen("t1.in","r",stdin);
scanf("%s",str+);
n=strlen(str+);
man[]='$',man[]='#';
int i,j,mr=,mid=,l,r,x;
SAM::init();
for(i=;i<=n;i++) SAM::insert(idx(str[i]),i);
SAM::build();
for(i=;i<=n;i++) man[*i]=str[i],man[*i+]='#';
p[]=;
ll ans=;
for(i=;i<=*n+;i++)
{
if(i<mr) p[i]=min(p[*mid-i],mr-i);
else p[i]=;
while(man[i-p[i]]==man[i+p[i]])
{
if(!((i+p[i])&))
{
l=(i-p[i])>>;
r=(i+p[i])>>;
x=SAM::pos[r];
ans=max(ans,1ll*(r-l+)*SAM::solve(x,l,r));
}
p[i]++;
}
if(i+p[i]>mr) mr=i+p[i],mid=i;
}
for(i=;i<=n;i++)
if(!hs[idx(str[i])])
{
hs[idx(str[i])]=;
l=i,r=i,x=SAM::pos[r];
ans=max(ans,1ll*SAM::solve(x,l,r));
}
printf("%lld\n",ans);
return ;
}
进入正题
这明明是一道$PAM$裸题嘛
$PAM$的构造方式类似于$AC$自动机..但它仍然有许多美妙的性质
比如奇回文树是树根节点深度设为-1等等...
而且$PAM$代码非常短
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 301000
#define S1 (N1<<1)
#define ll long long
#define uint unsigned int
#define rint register int
#define dd double
#define il inline
#define inf 0x3f3f3f3f
#define idx(X) (X-'a')
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,len,cnt;
namespace PAM{
int trs[N1][],pre[N1],dep[N1],sz[N1],la,tot;
void init(){la=tot=,pre[]=pre[]=,dep[]=-;}
int ntsym(char *str,int i,int p){return str[i-dep[p]-]!=str[i]?:;}
void insert(char *str,int i)
{
int p=la,np,fp,c=idx(str[i]);
while(ntsym(str,i,p)) p=pre[p];
if(!trs[p][c])
{
np=++tot;
dep[np]=dep[p]+;
fp=pre[p];
while(ntsym(str,i,fp)) fp=pre[fp];
pre[np]=trs[fp][c];
trs[p][c]=np;
}
la=trs[p][c];
sz[trs[p][c]]++;
return;
}
ll topo()
{
ll ans=;
for(int x=tot;x>;x--)
sz[pre[x]]+=sz[x],ans=max(ans,1ll*dep[x]*sz[x]);
return ans;
}
};
char str[N1]; int main()
{
//freopen("t2.in","r",stdin);
//freopen("a.out","w",stdout);
int i;PAM::init();
scanf("%s",str+);len=strlen(str+);
for(i=;i<=len;i++) PAM::insert(str,i);
printf("%lld\n",PAM::topo());
return ;
}
BZOJ 3676 [Apio2014]回文串 (后缀自动机+manacher/回文自动机)的更多相关文章
- [bzoj3676]回文串[后缀数组+Manacher]
后缀数组+Manacher #include <iostream> #include <cstdio> #include <cstdlib> #include &l ...
- 力扣算法:125-验证回文串,131-分割回文串---js
LC 125-验证回文串 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 注:回文串是正着读和反着读都一样的字符串. ...
- bzoj 3676: [Apio2014]回文串 回文自动机
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 844 Solved: 331[Submit][Status] ...
- 字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串
Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行 ...
- bzoj 3676: [Apio2014]回文串【回文自动机】
回文自动机板子 或者是SAM+manacher+倍增,就是manacher求本质不同回文串(让f++的串),然后在SAM倍增查询对应点出现次数 #include<iostream> #in ...
- BZOJ 3676: [Apio2014]回文串
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2013 Solved: 863[Submit][Status ...
- 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2343 Solved: 1031 Description 考 ...
- bzoj 3676 [Apio2014]回文串(Manacher+SAM)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题意] 给定一个字符串,定义一个串的权值为长度*出现次数,求最大权的回文子串. ...
- ●BZOJ 3676 [Apio2014]回文串
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3676 题解: 后缀数组,Manacher,二分 首先有一个结论:一个串的本质不同的回文串的个 ...
随机推荐
- XSS Chanllenges 1-5
XSS Chanllenges XSS Chanllenges 是一个XSS的练习平台,可以借助这个平台练习各种绕过,以及手工进行XSS的学习 平台链接:https://xss-quiz.int21h ...
- MVC架构之delegate
Qt的MVC架构可以实现很多数据显示的功能,本次主要对代理进行一个总结: 重实现QStyledItemDelegate类,实现自定义类. (1)ComboxDelegate.h #ifndef COM ...
- Linux 获取帮助
Linux中获取帮助的方法 方法: COMMAND --help 或者 help COMMAND whatis man或info 本地帮助文档 /usr/share/doc/ ...
- Jdk和Cglib 的区别
一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的代理类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...
- yii2.0 表单小部件常用的默认选中
下面自己总结了一下表单小部件中经常使用到的一些默认选中 直接在视图代码里面说明啦 <?php //这个表头就不多说了 use yii\helpers\Html; use yii\widgets\ ...
- [Tailwind] Style Elements on hover and focus with Tailwind’s State Variants
In this lesson, we learn how to target specific states of elements and apply styles only when those ...
- SQL注入原理以及怎样避免注入
SQL注入:究竟什么时候会用到SQL呢?回答是訪问数据库的时候.也就是说SQL注入-->直接威胁到了数据源,呵呵.数据库都收到了威胁,站点还能正常现实么? 所谓SQL注入,就是通过把SQL命令插 ...
- openssl之EVP系列之6---EVP_Encrypt系列函数编程架构及样例
openssl之EVP系列之6---EVP_Encrypt系列函数编程架构及样例 ---依据openssl doc/crypto/EVP_EncryptInit.pod和doc/ssleay. ...
- UFLDL教程笔记及练习答案五(自编码线性解码器与处理大型图像**卷积与池化)
自己主动编码线性解码器 自己主动编码线性解码器主要是考虑到稀疏自己主动编码器最后一层输出假设用sigmoid函数.因为稀疏自己主动编码器学习是的输出等于输入.simoid函数的值域在[0,1]之间,这 ...
- Javascript中的with用法
1.看例子 <script language="javascript"> function Lakers() { this.name = "kobe brya ...