由于本质不同的回文子串数量是O(n)的,考虑在对于每个回文子串在第一次找到它时对其暴力统计。可以发现manacher时若右端点移动则找到了一个新回文串。注意这样会漏掉串长为1的情况,特判一下。

  现在问题变为统计一个子串的出现次数。可以用SA,二分乱搞一下即可。这里使用SAM。以parent树上表示该子串的节点为起点,用倍增往上跳,找到深度最小的满足len限制的点就好了,出现次数就是其right集合的大小。

  uojAC,luoguRE一个点,bzojMLE……

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 600010
int n,last,cnt,len[N],fail[N],son[N][],size[N],pos[N>>],p[N];
long long ans=;
char s[N];
namespace tree
{
int p[N],t=,fa[N][];
struct data{int to,nxt;
}edge[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k)
{
for (int i=p[k];i;i=edge[i].nxt)
{
fa[edge[i].to][]=k;
dfs(edge[i].to);
size[k]+=size[edge[i].to];
}
}
void build()
{
for (int i=;i<=cnt;i++) addedge(fail[i],i);
fa[][]=;dfs();
for (int j=;j<;j++)
for (int i=;i<=cnt;i++)
fa[i][j]=fa[fa[i][j-]][j-];
}
int calc(int l,int r)
{
int x=pos[r];
for (int j=;~j;j--) if (len[fa[x][j]]>=r-l+) x=fa[x][j];
return size[x];
}
}
using tree::calc;
void ins(int c,int n)
{
int x=++cnt,p=last;last=x;len[x]=n;size[x]=;pos[n]=x;
while (!son[p][c]&&p) son[p][c]=x,p=fail[p];
if (!p) fail[x]=;
else
{
int q=son[p][c];
if (len[p]+==len[q]) fail[x]=q;
else
{
int y=++cnt;len[y]=len[p]+;
memcpy(son[y],son[q],sizeof(son[q]));
fail[y]=fail[q];fail[q]=fail[x]=y;
while (son[p][c]==q) son[p][c]=y,p=fail[p];
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj3676.in","r",stdin);
freopen("bzoj3676.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
last=cnt=;
scanf("%s",s+);n=strlen(s+);
for (int i=;i<=n;i++) ins(s[i]-,i);
tree::build();
for (int i=n;i>=;i--) s[i*-]=s[i];
for (int i=;i<n;i++) s[i<<]='$';
int x=;
for (int i=;i<=n;i++) ans=max(ans,1ll*calc(i,i));
for (int i=;i<n*;i++)
{
if (x+p[x]>i) p[i]=min(x+p[x]-i,p[x-(i-x)]);
while (i-p[i]->=&&i+p[i]+<n*&&s[i+p[i]+]==s[i-p[i]-])
{
p[i]++;
if (s[i+p[i]]!='$') ans=max(ans,1ll*((i+p[i]>>)-(i-p[i]>>)+)*calc((i-p[i]>>)+,(i+p[i]>>)+));
}
if (i+p[i]>x+p[x]) x=i;
}
cout<<ans;
return ;
}

BZOJ3676 APIO2014回文串(manacher+后缀自动机)的更多相关文章

  1. [bzoj3676][Apio2014]回文串——Manacher+后缀自动机+倍增

    Brief Description 一个回文串的value定义为这个回文串的长度乘以出现次数.给定一个字符串,求\(value_{max}\). Algorithm Design 我们使用Manach ...

  2. [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3396  Solved: 1568[Submit][Statu ...

  3. 2018.12.15 bzoj3676: [Apio2014]回文串(后缀自动机)

    传送门 对原串建立一个后缀自动机,然后用反串在上面匹配. 如果当前匹配的区间[l,r][l,r][l,r]包裹了当前状态的endposendposendpos中的最大值,那么[l,maxpos][l, ...

  4. [BZOJ3676][APIO2014]回文串(Manacher+SAM)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3097  Solved: 1408[Submit][Statu ...

  5. BZOJ3676 APIO2014 回文串 Manacher、SA

    传送门 首先一个结论:串\(S\)中本质不同的回文串个数最多有\(|S|\)个 证明考虑以点\(i\)结尾的所有回文串,假设为\(S[l_1,i],S[l_2,i],...,S[l_k,i]\),其中 ...

  6. [APIO2014]回文串 manacher 后缀数组

    题面:洛谷 题解: 还是这个性质:对于每个串而言,本质不同的回文串最多只有O(n)个. 所以我们先求出这O(n)个本质不同的回文串,然后对整个串求一次sa. 然后对于每个回文串,求出它的出现次数,更新 ...

  7. bzoj 3676: [Apio2014]回文串【后缀自动机+manacher】

    用manacher找出本质不同的回文子串放在SAM上跑 #include<iostream> #include<cstdio> #include<cstring> ...

  8. [模板] 回文树/回文自动机 &amp;&amp; BZOJ3676:[Apio2014]回文串

    回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...

  9. bzoj3676 [Apio2014]回文串 卡常+SAM+树上倍增

    bzoj3676 [Apio2014]回文串 SAM+树上倍增 链接 bzoj luogu 思路 根据manacher可以知道,每次暴力扩展才有可能出现新的回文串. 所以推出本质不同的回文串个数是O( ...

随机推荐

  1. CSS3鼠标悬停图片上浮显示描述代码

    效果:http://hovertree.com/texiao/css3/20/ 效果图: 代码如下: <!doctype html> <html lang="zh" ...

  2. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  3. Android Framework

    简介 之前的研究太偏向应用层功能实现了,很多原理不了解没有深究,现在研究framework框架层了. 记录 1.下载源码,目录如下: 2.Android系统的层次如下: 3.项目目录简单分析如下:

  4. oracle删除users表空间

    1.users表空间一般情况下是默认的,需将别的空间设置成默认,再删除users表空间(oracle不允许删除默认空间的). 2.删除表空间的同时会报这样的错:ORA-22868错误.原因:推断应该存 ...

  5. Mongoose全面理解

    一.创建schemas 创建schemas的方式: 1 var userSchema = new mongoose.Schema({ 2 name: String, 3 email: String, ...

  6. Json 返回日期格式转换

    //日期转换 function ChangeDateFormat(time) { if (time != null) { var date = new Date(parseInt(time.repla ...

  7. tengine rpm制作

    最近又在centos6.4下折腾tengine了,刚好不久前看了rpm包的制作方法,所以又有了搞个rpm包的想法. 1 安装centos的开发环境集成包及tengine的依赖包 1 yum group ...

  8. delphi json(CDS包含了Delta数据包)

    在delphi中,数据集是最常用数据存取方式.因此,必须建立JSON与TDataSet之间的互转关系,实现数据之间通讯与转换.值得注意的是,这只是普通的TDataset与JSON之间转换,由于CDS包 ...

  9. HDOJ/HDU 2717 Catch That Cow 一维广度优先搜索 so easy..............

    看题:http://acm.hdu.edu.cn/showproblem.php?pid=2717 思路:相当于每次有三个方向,加1,减1,乘2,要注意边界条件,减1不能小于0,乘2不能超过最大值. ...

  10. 【AGC013C】Ants on a Circle 弹性碰撞

    题目大意 一个长度为\(lm\)的环上有\(n\)只蚂蚁,告诉你每只蚂蚁的位置和朝向,每只蚂蚁会向前爬,速度为\(1m/s\),两只蚂蚁相遇后都会掉头,问你\(t\)秒后每只蚂蚁的位置. \(n\le ...