【题解】回文串 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 学会了字符串之后,精通各种字符串算法,比如……判断一个字符串是不是回文串. ...
随机推荐
- 孤荷凌寒自学python第八十五天配置selenium并进行模拟浏览器操作1
孤荷凌寒自学python第八十五天配置selenium并进行模拟浏览器操作1 (完整学习过程屏幕记录视频地址在文末) 要模拟进行浏览器操作,只用requests是不行的,因此今天了解到有专门的解决方案 ...
- 【转】: 探索Lua5.2内部实现:虚拟机指令(1) 概述
Lua一直把虚拟机执行代码的效率作为一个非常重要的设计目标.而采用什么样的指令系统的对于虚拟机的执行效率来说至关重要. Stack based vs Register based VM 根据指令获取操 ...
- BFC与合并 浅析
BFC BFC 全称 Block Formatting Context.每个渲染区域用formatting context表示,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用在正常流中的盒 ...
- ThreadLocal 线程的私有内存
话说在<操作系统原理>这门课里面,我们学到了很多概念:进程.线程.锁.PV操作.读写者问题等等,大家还记得么?(估计有些概念早已忘记了吧,哈哈哈~) 其中关于进程.线程和锁的东西是我们平时 ...
- DeepLearning Intro - sigmoid and shallow NN
This is a series of Machine Learning summary note. I will combine the deep learning book with the de ...
- 关于mysql开元数据库的几个随想
现在已经是凌晨了,昨天晚上写了我人生中的第一篇笔记,觉得没什么可写的,写了一个多小时都没写出什么,现在突然想写点东西了,这是一个比较有趣的问题,前两个月换了新工作,记得当初面试这份工作的时候面试到第三 ...
- Python 服务器端表单验证插件
Python格式验证库 Cerberus 作者 MrStranger 关注 2016.08.02 14:44 字数 2140 阅读 79评论 0喜欢 1 Cerberus是一个验证Python对象.M ...
- scrapy(2)——scrapy爬取新浪微博(单机版)
Sina爬虫教程 Scrapy环境搭建 环境:window10 + python2.7(包含scrapy)+ mongoDB 1.1 安装集成了python2.7的anaconda ana ...
- lintcode-11-二叉查找树中搜索区间
二叉查找树中搜索区间 给定两个值 k1 和 k2(k1 < k2)和一个二叉查找树的根节点.找到树中所有值在 k1 到 k2 范围内的节点.即打印所有x (k1 <= x <= k2 ...
- python urllib使用
Urllib是python内置的HTTP请求库包括以下模块urllib.request 请求模块urllib.error 异常处理模块urllib.parse url解析模块urllib.robotp ...