BZOJ3676 APIO2014 回文串 Manacher、SA
首先一个结论:串\(S\)中本质不同的回文串个数最多有\(|S|\)个
证明考虑以点\(i\)结尾的所有回文串,假设为\(S[l_1,i],S[l_2,i],...,S[l_k,i]\),其中\(l_1 < l_2 < ... < l_k\),那么因为\(S[l_i,i]\)是个回文串,所以\(S[l_2,i] = S[l_1,l_1 + i - l_2]\),那么这个串可以在以点\(l_1 + i - l_2\)结尾的字符串中被考虑到,当前无需考虑。所以对于以\(i\)结尾的所有串,只有\(S[l_1,i]\)需要考虑。所以以\(i\)结尾的所有回文串至多会生成出一个本质不同的回文串,所以至多有\(|S|\)个本质不同的回文串。
跑一边\(Manacher\)将上面的\(S[l_1,i]\)中的\(l_1\)计算出来,然后在\(SA\)里计算一下与\(suf_{l_1}\)的LCP大于等于\(i - l_1 + 1\)的后缀数量,就是这个串在\(S\)中的出现次数。
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
//This code is written by Itst
using namespace std;
const int MAXN = 3e5 + 7;
char s[MAXN];
int L;
namespace SA{
int pot[MAXN << 1] , rk[MAXN << 1] , sa[MAXN] , tp[MAXN << 1] , h[MAXN];
int maxN , logg2[MAXN] , ST[21][MAXN];
void sort(int p){
memset(pot , 0 , sizeof(int) * (maxN + 1));
for(int i = 1 ; i <= L ; ++i)
++pot[rk[i]];
for(int i = 1 ; i <= maxN ; ++i)
pot[i] += pot[i - 1];
for(int i = 1 ; i <= L ; ++i)
sa[++pot[rk[tp[i]] - 1]] = tp[i];
swap(tp , rk);
for(int i = 1 ; i <= L ; ++i)
rk[sa[i]] = rk[sa[i - 1]] + (tp[sa[i]] != tp[sa[i - 1]] || tp[sa[i] + p] != tp[sa[i - 1] + p]);
maxN = rk[sa[L]];
}
void init_ST(){
for(int i = 2 ; i <= L ; ++i)
logg2[i] = logg2[i >> 1] + 1;
for(int i = 2 ; i <= L ; ++i)
ST[0][i] = h[i];
for(int i = 1 ; 1 << i <= L - 1 ; ++i)
for(int j = 2 ; j + (1 << i) - 1 <= L ; ++j)
ST[i][j] = min(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
}
void init(){
scanf("%s" , s + 1);
L = strlen(s + 1);
maxN = 26;
for(int i = 1 ; i <= L ; ++i)
rk[tp[i] = i] = s[i] - 'a' + 1;
sort(0);
for(int i = 1 ; maxN != L ; i <<= 1){
int cnt = 0;
for(int j = 1 ; j <= i ; ++j)
tp[++cnt] = L - i + j;
for(int j = 1 ; j <= L ; ++j)
if(sa[j] > i)
tp[++cnt] = sa[j] - i;
sort(i);
}
for(int i = 1 ; i <= L ; ++i){
if(rk[i] == 1) continue;
int t = rk[i];
h[t] = max(0 , h[rk[i - 1]] - 1);
while(s[sa[t] + h[t]] == s[sa[t - 1] + h[t]])
++h[t];
}
init_ST();
}
int qST(int x , int y){
if(x > y) x ^= y ^= x ^= y;
int t = logg2[y - x + 1];
return min(ST[t][x] , ST[t][y - (1 << t) + 1]);
}
long long work(int pos , int len){
int ansL , l = 1 , r = rk[pos];
while(l < r){
int mid = (l + r) >> 1;
qST(mid + 1 , rk[pos]) >= len ? r = mid : l = mid + 1;
}
ansL = l;
l = rk[pos]; r = L;
while(l < r){
int mid = (l + r + 1) >> 1;
qST(rk[pos] + 1 , mid) >= len ? l = mid : r = mid - 1;
}
return 1ll * (r - ansL + 1) * len;
}
}
namespace manacher{
int maxL[MAXN << 1] , minL[MAXN];
char S[MAXN << 1];
void work(){
for(int i = 1 ; i <= L ; ++i)
S[(i << 1) - 1] = s[i];
int maxR = 0 , maxI = 1;
for(int i = 1 ; i < (L << 1) ; ++i){
int l = min(maxL[2 * maxI - i] , maxR - i);//曾经把min写成了max。。。
while(l <= i && i + l <= (L << 1) && S[i - l] == S[i + l])
++l;
maxL[i] = l;
if(l + i > maxR){
maxR = l + i;
maxI = i;
}
}
memset(minL , 0x3f , sizeof(minL));
for(int i = 1 ; i < (L << 1) ; ++i)
minL[(maxL[i] + i - 1) >> 1] = min(minL[(maxL[i] + i - 1) >> 1] , ((i - maxL[i] + 1) >> 1) + 1);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
SA::init();
manacher::work();
long long ans = 0;
for(int i = 1 ; i <= L ; ++i)
if(manacher::minL[i] <= i)
ans = max(ans , SA::work(manacher::minL[i] , i - manacher::minL[i] + 1));
cout << ans;
return 0;
}
BZOJ3676 APIO2014 回文串 Manacher、SA的更多相关文章
- [BZOJ3676][APIO2014]回文串(Manacher+SAM)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3097 Solved: 1408[Submit][Statu ...
- [bzoj3676][Apio2014]回文串——Manacher+后缀自动机+倍增
Brief Description 一个回文串的value定义为这个回文串的长度乘以出现次数.给定一个字符串,求\(value_{max}\). Algorithm Design 我们使用Manach ...
- bzoj3676 [Apio2014]回文串 卡常+SAM+树上倍增
bzoj3676 [Apio2014]回文串 SAM+树上倍增 链接 bzoj luogu 思路 根据manacher可以知道,每次暴力扩展才有可能出现新的回文串. 所以推出本质不同的回文串个数是O( ...
- [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串
回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...
- [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3396 Solved: 1568[Submit][Statu ...
- BZOJ3676 APIO2014回文串(manacher+后缀自动机)
由于本质不同的回文子串数量是O(n)的,考虑在对于每个回文子串在第一次找到它时对其暴力统计.可以发现manacher时若右端点移动则找到了一个新回文串.注意这样会漏掉串长为1的情况,特判一下. 现在问 ...
- BZOJ3676: [Apio2014]回文串(SAM+Manacher/PAM)
Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行 ...
- [APIO2014]回文串 manacher 后缀数组
题面:洛谷 题解: 还是这个性质:对于每个串而言,本质不同的回文串最多只有O(n)个. 所以我们先求出这O(n)个本质不同的回文串,然后对整个串求一次sa. 然后对于每个回文串,求出它的出现次数,更新 ...
- 【回文自动机】bzoj3676 [Apio2014]回文串
回文自动机讲解!http://blog.csdn.net/u013368721/article/details/42100363 pam上每个点代表本质不同的回文子串.len(i)代表长度,cnt(i ...
随机推荐
- 【读书笔记】iOS-使用蓝牙
蓝牙是由Sony Ericsso公司研发出来的,它是一种无线通讯协议,主要用于短程和低耗电设备,其有效通讯范围约30ft,传输速度为1MB/s.与Wifi设计初衷不同,蓝牙适用于无线的外围设备,进行小 ...
- vue-cli脚手架目录一览
最近在学习vue,看的稀里糊涂.今天从头开始,把cli配置的vue项目目录和配置文件搞清楚. 先看看整个项目目录结构: 再看看build文件夹下相关文件及目录: config文件夹下目录和文件: 接下 ...
- DB、ETL、DW、OLAP、DM、BI关系 ZT
在此大概用口水话简单叙述一下他们几个概念: (1)DB/Database/数据库——这里一般指的就是OLTP数据库,在线事物数据库,用来支持生产的,比如超市的买卖系统.DB保留的是数据信息的最新状态, ...
- Nginx下配置网站SSL实现https访问本站就是用的这方法
本文出至:新太潮流网络博客 第一步:服务器环境,lnmp即Linux+Nginx+PHP+MySQL,本文中以我的博客为例,使用的是阿里云最低档的ECS+免费的Linux服务器管理系统WDCP快速搭建 ...
- python3 邮件发送
这是搜罗网络上的文章总结的一份文档, 参考: https://www.jb51.net/article/140604.htm https://www.jb51.net/article/140604.h ...
- Docker搭建wordpress博客环境(Centos7)
Docker搭建wordpress博客环境(Centos7) 升级系统 yum -y update 设置docker库 sudo yum install -y yum-utils sudo yum-c ...
- django项目中在settings中配置静态文件
STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static'), ] 写成大写可能看不太懂,但是小写的意思非常明显:staticfiles_dir = [ o ...
- parallels Desktop解决无法压缩硬盘的问题
使用pd12新建的win7虚拟机仅仅使用了四十个G,但在本地硬盘中的体现却是占用了一百左右:尝试压缩提示: 无法编辑硬盘属性,因为该硬盘有一个或多个快照. 该硬盘属于某一带有一个或多个快照的虚拟机.请 ...
- UITableView详解
一.建立 UITableView DataTable = [[UITableView alloc] initWithFrame:CGRectMake(, , , )]; [DataTable setD ...
- 使用POI读写word docx文件
目录 1 读docx文件 1.1 通过XWPFWordExtractor读 1.2 通过XWPFDocument读 2 写docx文件 2.1 直接通过XWPF ...