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,二分 首先有一个结论:一个串的本质不同的回文串的个 ...
随机推荐
- BZOJ 3110 [ZJOI2013]K大数查询 (整体二分+线段树)
和dynamic rankings这道题的思想一样 只不过是把树状数组换成线段树区间修改,求第$K$大的而不是第$K$小的 这道题还有负数,需要离散 #include <vector> # ...
- [NOIP 2010] 关押罪犯 (二分+二分图判定 || 并查集)
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"( ...
- OOA,OOD,OOP区别
定义: OOA(Object-Oriented Analysis,面向对象分析方法) OOD(Object-Oriented Design,面向对象设计) OOP(Object Oriented Pr ...
- Cocos2d切换场景出现的问题-error C2653: “***”不是类或命名空间名称
1,在开头引入头文件 2,在要引入的头文件中,去除以下代码: #ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #endif ...
- Untiy中的数据平滑处理
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/50680237 作者:car ...
- 使用Eclipse进行远程调控
什么是远程调试,就是在A机器上利用Eclipse单步跟踪调试B机器上的Web应用,当然调试A机器上Web应用也是没有问题的,90%我都是调试本机的Web应用,远程调试的意义我想我不用说了,大家都会想到 ...
- 在WPF的MVVM框架中获取下拉选择列表中的选中项
文章概述: 本演示介绍怎样在WPF的MVVM框架中.通过数据绑定的方式获取下拉列表中的选中项.程序执行后的效果例如以下图所看到的: 相关下载(代码.屏幕录像):http://pan.baidu.com ...
- [GraphQL] Mutations and Input Types
Sometimes, you want to resues object type when doing mutation, you can use 'input' type to help: inp ...
- python爬虫系列:Scrapy安装与使用
这篇博文主要写Scrapy框架的安装与使用 Scrapy框架安装 命令行进入C:\Anaconda2\Scripts目录,运行:conda install Scrapy 创建Scrapy项目 1)进入 ...
- IOS-2-C语言和Objective-C语言衔接学习资料
前言:在IOS学习中.通常会先学习一周的C语言,两周的Objective-C语言,这是今后开发的最基础最重要的部分,以下给大家分享一下培训课上的精简资料: C语言和Objective-C语言衔接学习资 ...