题目大意:

给你一个字符串,求其中回文子串的长度*出现次数的最大值

明明是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/回文自动机)的更多相关文章

  1. [bzoj3676]回文串[后缀数组+Manacher]

    后缀数组+Manacher #include <iostream> #include <cstdio> #include <cstdlib> #include &l ...

  2. 力扣算法:125-验证回文串,131-分割回文串---js

    LC 125-验证回文串 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 注:回文串是正着读和反着读都一样的字符串. ...

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

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 844  Solved: 331[Submit][Status] ...

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

    Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行 ...

  5. bzoj 3676: [Apio2014]回文串【回文自动机】

    回文自动机板子 或者是SAM+manacher+倍增,就是manacher求本质不同回文串(让f++的串),然后在SAM倍增查询对应点出现次数 #include<iostream> #in ...

  6. BZOJ 3676: [Apio2014]回文串

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2013  Solved: 863[Submit][Status ...

  7. 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2343  Solved: 1031 Description 考 ...

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

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3676 [题意] 给定一个字符串,定义一个串的权值为长度*出现次数,求最大权的回文子串. ...

  9. ●BZOJ 3676 [Apio2014]回文串

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3676 题解: 后缀数组,Manacher,二分 首先有一个结论:一个串的本质不同的回文串的个 ...

随机推荐

  1. Linux系统下的 /etc/fstab 文件解读

    1 [root@localhost ~]# cat /etc/fstab 2 3 # 4 # /etc/fstab 5 # Created by anaconda on Sat Nov 3 12:03 ...

  2. 循环时自动打开url

    'systemutil.Run "C:\Program Files (x86)\HP\QuickTest Professional\samples\flight\app\flight4a.e ...

  3. iwebshop 增删改查

    <?php header("content-type:text/html;charset=utf-8"); class Test extends IController { ...

  4. MySQL 的各种查询列子

    一.mysql查询的五种子句         where(条件查询).having(筛选).group by(分组).order by(排序).limit(限制结果数)           1.whe ...

  5. html5的postmessage实现js前端跨域訪问及调用解决方式

    关于跨域訪问.使用JSONP的方法.我前面已经demo过了.详细见http://supercharles888.blog.51cto.com/609344/856886,HTML5提供了一个很强大的A ...

  6. mbed

    mbed介绍--ARM最新面向IOT的RTOS与平台 文章为本人原创,转载请注明:http://blog.csdn.net/guo8113/article/details/40479303 mbed是 ...

  7. JavaScript 获取小数任一小数点后的位数的小数

    用Javascript取float型小数点后两位,例22.127456取成22.13,怎样做? 1.这样的方法最不推荐: function get(){ var s = 22.127456 + &qu ...

  8. json 与其他数据 格式转换及json学习新得

    jsonobject   var a={"a","A"}   通过json都对象能很轻松的操作json数据 jsonString     var a=" ...

  9. 分享几个可用的rtsp, http測试url

    rtsp://218.204.223.237:554/live/1/0547424F573B085C/gsfp90ef4k0a6iap.sdp rtsp://218.204.223.237:554/l ...

  10. gemm() 与 gesvd() 到矩阵求逆(inverse)(根据 SVD 分解和矩阵乘法求矩阵的逆)

    可逆方阵 A 的逆记为,A−1,需满足 AA−1=I. 在 BLAS 的各种实现中,一般都不会直接给出 matrix inverse 的直接实现,其实矩阵(方阵)的逆是可以通过 gemm()和gesv ...