这题可以用回文自动机来做,但是我并没有学,于是用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+后缀数组+二分的更多相关文章

  1. BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)

    题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...

  2. BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

  3. BZOJ 3676 【APIO2014】 回文串

    题目链接:回文串 我终于也会回文自动机辣! 其实吗……我觉得回文自动机(听说这玩意儿叫\(PAM\))还是比较\(simple\)的……至少比\(SAM\)友善多了…… 所谓回文自动机,每个节点就代表 ...

  4. bzoj 2565: 最长双回文串 回文自动机

    题目: Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同 ...

  5. BZOJ2565:最长双回文串——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2565 题目大意: 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(ab ...

  6. P3649 [APIO2014]回文串(回文树)

    题目描述 给你一个由小写拉丁字母组成的字符串 ss .我们定义 ss 的一个子串的存在值为这个子串在 ss 中出现的次数乘以这个子串的长度. 对于给你的这个字符串 ss ,求所有回文子串中的最大存在值 ...

  7. POJ 3974 回文串-Manacher

    题目链接:http://poj.org/problem?id=3974 题意:求出给定字符串的最长回文串长度. 思路:裸的Manacher模板题. #include<iostream> # ...

  8. manacher算法,求回文串

    用来求字符串最长回文串或者回文串的总数量 #include<map> #include<queue> #include<stack> #include<cma ...

  9. 牛客寒假算法基础集训营4 I Applese 的回文串

    链接:https://ac.nowcoder.com/acm/contest/330/I来源:牛客网 自从 Applese 学会了字符串之后,精通各种字符串算法,比如……判断一个字符串是不是回文串. ...

随机推荐

  1. git revert 与 git reset

    Git版本回滚之 git revert 与 git reset 在使用 git 的时候,如果错误push之后,经常会回滚版本. git的回滚有两种方式: revert命令:这种方式,是用一种反向的 p ...

  2. 技本功丨知否知否,Redux源码竟如此意味深长(上集)

    夫 子 说 元月二号欠下袋鼠云技术公号一篇关于Redux源码解读的文章,转眼月底,期间常被“债主”上门催债.由于年底项目工期比较紧,于是债务就这样被利滚利.但是好在这段时间有点闲暇,于是赶紧把这篇文章 ...

  3. 棋盘问题:dfs

    Description 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子 ...

  4. Logistic回归和SVM的异同

    这个问题在最近面试的时候被问了几次,让谈一下Logistic回归(以下简称LR)和SVM的异同.由于之前没有对比分析过,而且不知道从哪个角度去分析,一时语塞,只能不知为不知. 现在对这二者做一个对比分 ...

  5. hive创建外部表

    Create [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] ...

  6. HDU 1250 Hat's Fibonacci(高精度)

    Problem Description A Fibonacci sequence is calculated by adding the previous two members the sequen ...

  7. httpd 2.2.15 添加流媒体模块

    项目中使用的一直都是 httpd  2.2.15  用于播放视频资源,近期有个新产品上线发现快进视频会出现卡顿情况,因此添加了流媒体模块.(怀疑是新产品中的播放器进行了更改) 原文:http://li ...

  8. 【week2】结对编程-四则运算 及感想

    首先我要说一下,我得作业我尽力了,但是能力有限,还需练习. 四则运算,改进代码流程: 1.手动输入算式(属于中缀表达式) 2.将中缀表达式转化成后缀表达式 生成out数组 3.一个操作数栈,一个运算符 ...

  9. ES6之 =>箭头函数

    原文,请点此链接http://www.cnblogs.com/allenxieyusheng/p/5784728.html 1. 第一个函数 ()=>1 解析:其实这是一个匿名函数直接执行 (f ...

  10. IDEA编译的JAR包运行出现“没有主清单属性”

    运行编译好的包出现: 解决方案就是: 确保MANIFEST.MF文件在src/main/resources/META_INF/而不是src/main/java/META_INF/