【题解】回文串 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 学会了字符串之后,精通各种字符串算法,比如……判断一个字符串是不是回文串. ...
随机推荐
- 【springmvc+mybatis项目实战】杰信商贸-4.maven依赖+PO对+映射文件
上一篇我们附件的增删改查功能全部完成.但是我们的附件有一个字段叫做“类型”(ctype),这里我们要使用数据字典,所以对于这一块我们要进行修改. 首先介绍一下数据字典 数据字典它是一个通用结构,跟业务 ...
- 贪心算法——Huffman 压缩编码的实现
1. 如何理解 "贪心算法" 假设我们有一个可以容纳 100 Kg 物品的背包,可以装各种物品.我们有以下 5 种豆子,每种豆子的总量和总价值都各不相同.怎样装才能让背包里豆子的总 ...
- vue移动音乐app开发学习(三):轮播图组件的开发
本系列文章是为了记录学习中的知识点,便于后期自己观看.如果有需要的同学请登录慕课网,找到Vue 2.0 高级实战-开发移动端音乐WebApp进行观看,传送门. 完成后的页面状态以及项目结构如下: 一: ...
- protected、public、private
一.protected成员 1. 受保护的成员的可访问性 对于一个类的protected成员,①该类的用户(如类对象)不能访问它,②该类的派生类的成员(及其友元)可以访问它. 派生类的成员及其友元不能 ...
- Beta版本软件使用说明
北京航空航天大学计算机学院 远航1617 小组 产品版本: Beta版本 产品名称:Crawling is going on 文档作者:杨帆 文档日期:2013/12/24 1. 引言 1.1 ...
- iOS开发UUIView动画方法总结
#动画设置 UIView动画实现 @interface ViewController () @property (weak, nonatomic) IBOutlet UIView *myView; @ ...
- <Android>spinner/AutoCompleteTextView绑定适配器
position = (Spinner)findViewById(R.id.position); String[] str = {"CEO","CFO",&qu ...
- 转 Js 跨域CORS报错 Response for preflight has invalid HTTP status code 405
转自:http://www.cnblogs.com/SilenceTom/p/6697484.html 调用接口遇到Response for preflight has invalid HTTP st ...
- 从HR 到SBP其实还有很长的一段路要走
战略性业务伙伴 Strategic business partners 关于这本书,一般是因为好奇,从HR到BP的角色,再到这个SBP,其实是一段没有走过的很虚的过程,不过总归是需要灯塔,即使偶尔只是 ...
- Java SE1.6中的Synchronized
1 引言 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本 ...