【题解】回文串 APIO 2014 BZOJ 3676 COGS 1985 Manacher+后缀数组+二分
这题可以用回文自动机来做,但是我并没有学,于是用Manacher+SA的做法O(nlogn)水过
首先,看到回文串就能想到用Manacher
同样还是要利用Manacher能不重复不遗漏地枚举每个回文子串的性质
只是不重复不遗漏还不够,我们还要统计出现次数
每个子串一定是一个后缀的前缀,于是可以用后缀数组
用后缀数组求出height数组之后,对于在Manacher过程中枚举到的每个长度为k的回文串,可以在height数组中二分,用O(logn)的时间求出这个子串的出现次数
BZOJ和COGS上有评论说Manacher + SA的方式被卡了,也有人说自己跑了19s,我这个实现是在BZOJ上跑了10s,COGS的76组数据总共跑了3.7s。
代码如下:
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cctype> using namespace std;
typedef long long ll;
const int MAXN = , LOGN = ; int n;
char str[MAXN];
int sas[MAXN], san;
int mas[MAXN<<], man; namespace SA {
int sa[MAXN], rk[MAXN], ht[MAXN];
int tmp1[MAXN], tmp2[MAXN], cnt[MAXN];
int minv[MAXN][LOGN], logn[MAXN];
void solve( int m ) {
int *x = tmp1, *y = tmp2;
for( int i = ; i < m; ++i ) cnt[i] = ;
for( int i = ; i < san; ++i ) ++cnt[ x[i] = sas[i] ];
for( int i = ; i < m; ++i ) cnt[i] += cnt[i-];
for( int i = san-; i >= ; --i ) sa[--cnt[x[i]]] = i;
for( int k = ; k <= san; k <<= ) {
int p = ;
for( int i = san-k; i < san; ++i ) y[p++] = i;
for( int i = ; i < san; ++i ) if( sa[i] >= k ) y[p++] = sa[i]-k;
for( int i = ; i < m; ++i ) cnt[i] = ;
for( int i = ; i < san; ++i ) ++cnt[x[i]];
for( int i = ; i < m; ++i ) cnt[i] += cnt[i-];
for( int i = san-; i >= ; --i ) sa[--cnt[x[y[i]]]] = y[i];
swap(x,y), x[sa[]] = , p = ;
for( int i = ; i < san; ++i )
x[sa[i]] = y[sa[i]] == y[sa[i-]] && y[sa[i]+k] == y[sa[i-]+k] ? p- : p++;
if( p == san ) break;
m = p;
}
for( int i = ; i < san; ++i ) rk[i] = x[i];
int k = ;
for( int i = ; i < san; ++i ) {
if( k ) --k;
if( !rk[i] ) continue;
int j = sa[rk[i]-];
while( sas[i+k] == sas[j+k] ) ++k;
ht[rk[i]] = minv[rk[i]][] = k;
}
for( int k = ; (<<k) <= san; ++k )
for( int i = ; i+(<<k) <= san; ++i )
minv[i][k] = min( minv[i][k-], minv[i+(<<(k-))][k-] );
k = ;
for( int i = ; i <= san; ++i ) {
if( (<<(k+)) <= i ) ++k;
logn[i] = k;
}
}
int qmin( int l, int r ) {
int k = logn[r-l+];
return min( minv[l][k], minv[r+-(<<k)][k] );
}
} void input() {
scanf( "%s", str ), n = strlen(str);
man = ;
for( int i = ; i < n; ++i ) {
sas[i] = str[i];
mas[man++] = '#', mas[man++] = str[i];
}
sas[n] = , san = n+;
mas[man++] = '#';
SA::solve();
} ll ans = ;
int rd[MAXN<<];
void update( int p, int k ) {
using namespace SA;
p = rk[p];
int LL = , LR = p;
while( LL < LR ) {
int mid = (LL+LR)>>;
if( qmin(mid+,p) >= k ) LR = mid;
else LL = mid+;
}
int RL = p, RR = san-;
while( RL < RR ) {
int mid = (RL+RR+)>>;
if( qmin(p+,mid) >= k ) RL = mid;
else RR = mid-;
}
ans = max( ans, ll(k)*(RL-LL+) );
}
int cnt[] = {};
void manacher() {
int mx = , p = ;
for( int i = ; i < man; ++i ) {
if( i < mx ) rd[i] = min( rd[*p-i], mx-i );
else rd[i] = ;
while( i+rd[i] < man && i-rd[i] >= && mas[i+rd[i]] == mas[i-rd[i]] ) {
if( islower( mas[i-rd[i]] ) ) update( (i-rd[i])/, rd[i]+ );
++rd[i];
}
if( i+rd[i] > mx ) mx = i+rd[i], p = i;
}
for( int i = ; i < n; ++i )
ans = max( ans, (ll)++cnt[str[i]-'a'] );
printf( "%lld\n", ans );
} int main() {
// freopen( "apio2014_palindrome.in", "r", stdin );
// freopen( "apio2014_palindrome.out", "w", stdout );
input(), manacher();
return ;
}
【题解】回文串 APIO 2014 BZOJ 3676 COGS 1985 Manacher+后缀数组+二分的更多相关文章
- BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)
题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
- BZOJ 3676 【APIO2014】 回文串
题目链接:回文串 我终于也会回文自动机辣! 其实吗……我觉得回文自动机(听说这玩意儿叫\(PAM\))还是比较\(simple\)的……至少比\(SAM\)友善多了…… 所谓回文自动机,每个节点就代表 ...
- bzoj 2565: 最长双回文串 回文自动机
题目: Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同 ...
- BZOJ2565:最长双回文串——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2565 题目大意: 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(ab ...
- P3649 [APIO2014]回文串(回文树)
题目描述 给你一个由小写拉丁字母组成的字符串 ss .我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这个子串的长度. 对于给你的这个字符串 ss ,求所有回文子串中的最大存在值 ...
- POJ 3974 回文串-Manacher
题目链接:http://poj.org/problem?id=3974 题意:求出给定字符串的最长回文串长度. 思路:裸的Manacher模板题. #include<iostream> # ...
- manacher算法,求回文串
用来求字符串最长回文串或者回文串的总数量 #include<map> #include<queue> #include<stack> #include<cma ...
- 牛客寒假算法基础集训营4 I Applese 的回文串
链接:https://ac.nowcoder.com/acm/contest/330/I来源:牛客网 自从 Applese 学会了字符串之后,精通各种字符串算法,比如……判断一个字符串是不是回文串. ...
随机推荐
- 373. Partition Array by Odd and Even【LintCode java】
Description Partition an integers array into odd number first and even number second. Example Given ...
- 孤荷凌寒自学python第七十九天开始写Python的第一个爬虫9并使用pydocx模块将结果写入word文档
孤荷凌寒自学python第七十九天开始写Python的第一个爬虫9 (完整学习过程屏幕记录视频地址在文末) 今天在上一天的基础上继续完成对我的第一个代码程序的书写. 到今天终于完成了对docx模块针对 ...
- Machine Learning笔记整理 ------ (四)线性模型
1. 线性模型 基本形式:给定由d个属性描述的样本 x = (x1; x2; ......; xd),其中,xi是x在第i个属性上的取值,则有: f(x) = w1x1 + w2x2 + ...... ...
- Ext JS 6学习文档-第4章-数据包
Ext JS 6学习文档-第4章-数据包 数据包 本章探索 Ext JS 中处理数据可用的工具以及服务器和客户端之间的通信.在本章结束时将写一个调用 RESTful 服务的例子.下面是本章的内容: 模 ...
- BZOJ 4736 温暖会指引我们前行 LCT+最优生成树+并查集
题目链接:http://uoj.ac/problem/274 题意概述: 没什么好概述的......概述了题意就知道怎么做了......我懒嘛 分析: 就是用lct维护最大生成树. 然后如果去UOJ上 ...
- how to install pygraphviz on windows 10 with python 3.6
Here's what worked for me: Win 7 AMD64 Install MSFT C++ compiler. Install Anaconda for Win AMD64, Py ...
- OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
- object-oriented第二次作业(1)
1001.A+B F Format(20) 我的代码 题目看完,感觉挺简单的,就直接开始写代码了. 我把加起来后的数字的每位数用数组存起来,特判一下0和负数的情况,然后再一位位输出,遇到该输逗号的时候 ...
- OSG配置失败解决方案
这连续三天都在台式机上配置OSG,总是报各种各样的错. 后来换到笔记本上配置,结果一次性就配置成功了.笔记本和台式机都是WIN10系统,都是VS2013.或许有时候出错就可以换台电脑或者重装系统试试. ...
- Swoole和Swoft的那些事 (Http/Rpc服务篇)
https://www.jianshu.com/p/4c0f625d5e11 Swoft在PHPer圈中是一个门槛较高的Web框架,不仅仅由于框架本身带来了很多新概念和前沿的设计,还在于Swoft是一 ...