做法一:PAM;做法二:SAM+manacher.前缀树上倍增

Description

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

Input

输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。

Output

输出一个整数,为逝查回文子串的最大出现值。

【数据规模与评分】

数据满足1≤字符串长度≤300000。


题目分析

考虑暴力怎么做:首先对字符串$S$建立SAM,再使用manacher对所有$O(n)$级别的本质不同的回文子串查询出现个数。由于每次查询是$O(n)$的,所以暴力的复杂度是$O(n^2)$.

有一种SAM上计数的基本套路:在前缀树上倍增或是其他在树上的常规操作。对于这题则是考虑用倍增快速查询$S(l,r)$在全串中的出现次数。

用$fa[i][j]$表示点$i$在前缀树上向上跳$2^j$步的父亲点数,那么从$p=id[r]$(即子串$S(1,r)$插入完毕的一部分SAM)开始查询,若$len[p]≥r-l+1$就说明点$p$所在的子树仍都是$S(l,r)$的后缀,因此一直向上跳直到不满足限制的点$p$的$size[p]$就是回文子串$S(l,r)$出现次数。

 #include<bits/stdc++.h>
const int maxn = ; int n,g[maxn],lg2[maxn>>];
long long ans;
int size[maxn],dep[maxn],id[maxn],sta[maxn];
int cnt[maxn],pos[maxn];
char s[maxn],t[maxn];
struct SAM
{
int lst,tot;
int fa[maxn][],len[maxn];
std::map<int, int> ch[maxn];          //似乎略卡空间
SAM(){lst = tot = ;}
void extend(int c, int id)
{
int p = lst, np = ++tot;
lst = np, len[np] = len[p]+, sta[id] = np; //sta[np]=id
for (; p&&!ch[p][c]; p=fa[p][]) ch[p][c] = np;
if (!p) fa[np][] = ;
else{
int q = ch[p][c];
if (len[q]==len[p]+) fa[np][] = q;
else{
int nq = ++tot;
len[nq] = len[p]+, ch[nq] = ch[q];
fa[nq][] = fa[q][], fa[q][] = fa[np][] = nq;
for (; ch[p][c]==q; p=fa[p][]) ch[p][c] = nq;
}
}
size[np] = ;
}
void build()
{
for (int i=; i<=tot; i++) ++cnt[len[i]];
for (int i=; i<=tot; i++) cnt[i] += cnt[i-];
for (int i=tot; i>=; i--) pos[cnt[len[i]]--] = i;
for (int i=tot; i>=; i--)
size[fa[pos[i]][]] += size[pos[i]];
for (int i=; i<=tot; i++)
{
int p = pos[i];
dep[p] = dep[fa[p][]]+;
for (int j=; j<=; j++)
fa[i][j] = fa[fa[i][j-]][j-];
}
}
void match(int l, int r)
{
if (l > r||l < ||r > n) return;
int p = sta[r];
for (int i=lg2[dep[p]]; i>=; i--)
{
int fat = fa[p][i];
if (len[fat] >= r-l+) p = fat;
}
ans = std::max(ans, 1ll*size[p]*(r-l+));
}
}f; void manacher()
{
int m = , mid = ;
t[] = '!', t[++m] = '@';
for (int i=; i<=n; i++)
t[++m] = s[i], id[m] = i, t[++m] = '@';
for (int i=, mx=-; i<m; i++)
{
if (i >= mx) g[i] = ;
else g[i] = std::min(mx-i, g[*mid-i]);
f.match(id[i-g[i]+], id[i+g[i]-]);
for (; t[i-g[i]]==t[i+g[i]]; )
++g[i], f.match(id[i-g[i]+], id[i+g[i]-]); //id[i-g[i]], id[i+g[i]]
if (i+g[i] > mx) mx = i+g[i], mid = i;
}
}
int main()
{
scanf("%s",s+);
n = strlen(s+);
for (int i=; i<=n; i++)
f.extend(s[i]-'a', i), lg2[i] = i>?(lg2[i>>]+):;
f.build();
manacher();
printf("%lld\n",ans);
return ;
}

END

【SAM manacher 倍增】bzoj3676: [Apio2014]回文串的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. BZOJ3676: [Apio2014]回文串(SAM+Manacher/PAM)

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

  7. BZOJ3676 APIO2014回文串(manacher+后缀自动机)

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

  8. BZOJ3676 APIO2014 回文串 Manacher、SA

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

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

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

  10. 【回文自动机】bzoj3676 [Apio2014]回文串

    回文自动机讲解!http://blog.csdn.net/u013368721/article/details/42100363 pam上每个点代表本质不同的回文子串.len(i)代表长度,cnt(i ...

随机推荐

  1. 2、kvm基础常用命令操作

    KVM 虚拟机默认的配置文件在 /etc/libvirt/qemu 目录下,默认是以虚拟机名称命名的.xml文件,如下: root@xuedianhu:~# ls /etc/libvirt/qemu ...

  2. VALID_FOR in db standby

    检查DG 装填: 目标主机检查mrp是否正常: SELECT PROCESS FROM V$MANAGED_STANDBY WHERE PROCESS LIKE 'MRP%';--若mrp没有启动,则 ...

  3. 【C#】C#委托使用详解(Delegates)

    摘要 委托是C#编程一个非常重要的概念,也是一个难点.本文将系统详细讲解委托. 1. 委托是什么? 其实,我一直思考如何讲解委托,才能把委托说得更透彻.说实话,每个人都委托都有不同的见解,因为看问题的 ...

  4. 【ros depthimage_to_laser kinect2】

    kinect2的深度图可以转换成激光来用,使用depthimage_to_laser 这个tf是用来给rviz显示的 1)开启kinect2 rosrun kinect2_bridge kinect2 ...

  5. SQL重复记录查询-count与group by having结合查询重复记录

    查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断select * from peoplewhere peopleId in (select  peopleId  from  p ...

  6. C# linq根据自定义筛选条件和所对应的数值进行筛选

    在软件应用中有时候会出现这样的界面:上面是利用多选框和下拉框组合的筛选条件.下面表格展示筛选后的数据.如下图 上面是筛选条件,表格是根据筛选条件筛选的结果. 如果表格不支持筛选功能.可以利用Linq对 ...

  7. 实战:ADFS3.0单点登录系列-集成Exchange

    本文将介绍如何将Exchange与ADFS集成,从而实现对于Exchange的SSO. 目录: 实战:ADFS3.0单点登录系列-总览 实战:ADFS3.0单点登录系列-前置准备 实战:ADFS3.0 ...

  8. 【Python音乐生成】可能有用的一些Python库

    1,Python-MIDI,很多操作库的前置库.作者提供了一个python3的branch.git clone下来之后注意切换到这个branch之后再运行setup.py. 实际使用的时候,使用 im ...

  9. 两数相除赋值整数变量(T-SQL)

    MSSQL: DECLARE @_pagecount INT; ; SELECT @_pagecount; 结果为1 Mysql: BEGIN DECLARE _pagecount INT; ; SE ...

  10. HDU3874 线段树 + 离线处理

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3874 , 线段树(或树状数组) + 离线处理 下午做了第一道离线处理的题目(HDU4417),多少有点 ...