思路:用马拉车把一个串中的回文串个数降到O(n)级别,然后每个串在后缀自动机上倍增找个数。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
#define PLI pair<LL, int>
#define ull unsigned long long
using namespace std; const int N = + ;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + ;
const double eps = 1e-;
const int base = ; int n, m, p[N<<];
char s[N<<]; struct SuffixAutomaton {
int last, cur, cnt, ch[N<<][], id[N<<], fa[N<<], dis[N<<], sz[N<<], c[N];
int f[N<<][], pos[N<<];
SuffixAutomaton() {cur = cnt = ;}
void init() {
for(int i = ; i <= cnt; i++) {
memset(ch[i], , sizeof(ch[i]));
sz[i] = c[i] = dis[i] = fa[i] = ;
}
cur = cnt = ;
}
void extend(int c, int id) {
last = cur; cur = ++cnt;
int p = last; dis[cur] = id;
for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = cur;
if(!p) fa[cur] = ;
else {
int q = ch[p][c];
if(dis[q] == dis[p]+) fa[cur] = q;
else {
int nt = ++cnt; dis[nt] = dis[p]+;
memcpy(ch[nt], ch[q], sizeof(ch[q]));
fa[nt] = fa[q]; fa[q] = fa[cur] = nt;
for(; ch[p][c]==q; p=fa[p]) ch[p][c] = nt;
}
}
sz[cur] = ;
}
void getSize(int n) {
for(int i = ; i <= cnt; i++) c[dis[i]]++;
for(int i = ; i <= n; i++) c[i] += c[i-];
for(int i = cnt; i >= ; i--) id[c[dis[i]]--] = i;
for(int i = cnt; i >= ; i--) {
int p = id[i];
sz[fa[p]] += sz[p];
}
}
LL query(int p, int len) {
for(int j = ; j >= ; j--) {
if(f[p][j] && dis[f[p][j]] >= len) p = f[p][j];
}
return 1ll*len*sz[p];
}
void solve() {
for(int i = , p = ; i <= n; i++)
p = ch[p][s[i]-'a'], pos[i] = p;
for(int i = ; i <= cnt; i++) f[i][] = fa[i];
for(int j = ; j < ; j++)
for(int i = ; i <= cnt; i++)
f[i][j] = f[f[i][j-]][j-]; LL ans = ;
s[] = '-', s[n+] = '+';
int mx = , id = ;
for(int i = ; i <= n; i++) {
if(mx > i) p[i] = min(mx-i, p[*id-i]);
else p[i]=, ans = max(ans, query(pos[i], ));
while(s[i+p[i]]==s[i-p[i]]) p[i]++, ans = max(ans, query(pos[i+p[i]-], *p[i]-));
if(i+p[i]>mx) mx = i+p[i], id = i;
}
mx = , id = ;
for(int i = ; i <= n; i++) {
if(mx > i) p[i] = min(mx-i, p[*id-i]);
else p[i] = ;
while(s[i+p[i]+]==s[i-p[i]]) p[i]++, ans = max(ans, query(pos[i+p[i]], *p[i]));
if(i+p[i]>mx) mx = i+p[i], id = i;
}
printf("%lld\n", ans);
}
} sam; int main() {
scanf("%s", s + );
n = strlen(s + );
for(int i = ; i <= n; i++)
sam.extend(s[i]-'a', i);
sam.getSize(n);
sam.solve();
return ;
} /*
*/

bzoj 3676 后缀自动机+马拉车+树上倍增的更多相关文章

  1. HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)

    layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...

  2. 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)

    题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...

  3. bzoj 3473 后缀自动机多字符串的子串处理方法

    后缀自动机处理多字符串字串相关问题. 首先,和后缀数组一样,用分割符连接各字符串,然后建一个后缀自动机. 我们定义一个节点代表的字符串为它原本代表的所有串去除包含分割符后的串.每个节点代表的字符串的数 ...

  4. LOJ3049 [十二省联考2019] 字符串问题 【后缀自动机】【倍增】【拓扑排序】

    题目分析: 建出后缀自动机,然后把A串用倍增定位到后缀自动机上,再把B串用倍增定位到后缀自动机上. SAM上每个点上的A串根据长度从小到大排序,建点,依次连边. 再对于SAM上面每个点,连到儿子的边, ...

  5. BZOJ3998: [TJOI2015]弦论(后缀自动机,Parent树)

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  6. 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

    题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...

  7. CF666E Forensic Examination 广义后缀自动机_线段树合并_树上倍增

    题意: 给定一个串 $S$ 和若干个串 $T_{i}$每次询问 $S[pl..pr]$ 在 $Tl..Tr$ 中出现的最多次数,以及出现次数最多的那个串的编号. 数据范围: 需要离线 题解:首先,很常 ...

  8. 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2343  Solved: 1031 Description 考 ...

  9. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

随机推荐

  1. linux diff 命令

    diff 命令是 linux上非常重要的工具,用于比较文件的内容,特别是比较两个版本不同的文件以找到改动的地方.diff在命令行中打印每一个行的改动.最新版本的diff还支持二进制文件.diff程序的 ...

  2. CF&&CC百套计划1 Codeforces Round #449 C. Willem, Chtholly and Seniorious (Old Driver Tree)

    http://codeforces.com/problemset/problem/896/C 题意: 对于一个随机序列,执行以下操作: 区间赋值 区间加 区间求第k小 区间求k次幂的和 对于随机序列, ...

  3. bzoj千题计划135:bzoj1066: [SCOI2007]蜥蜴

    http://www.lydsy.com/JudgeOnline/problem.php?id=1066 每个柱子拆成两个点 i<<1,i<<1|1,之间连流量为高度的边 如果 ...

  4. Could not open input file: artisan

    执行php artisan 命令,报错Could not open input file: artisan artisan 是 Laravel 项目下的指令文件,在Laravel 项目的根目录下可以看 ...

  5. Is it possible to create @Around Aspect for feign.Client

    https://github.com/spring-cloud/spring-cloud-openfeign/issues/59 看到github 有人问这个问题,做了个示例: import org. ...

  6. zookeeper图形工具——zkui

    虽然zookeeper安装包提供了客户端工具zkcli,但是命令特别少 ,每次想看看里面的节点信息特别费劲. 幸好有图形工具——zkui,https://github.com/echoma/zkui, ...

  7. Javascript的V8引擎研究

    1.针对上下文的Snapshot技术 什么是上下文(Contexts)?实际是JS应用程序的运行环境,避免应用程序的修改相互影响,例如一个页面js修改内置对象方法toString,不应该影响到另外页面 ...

  8. 20155231 2016-2017-2 《Java程序设计》第7周学习总结

    20155231 2016-2017-2 <Java程序设计>第7周学习总结 教材学习内容总结 学习目标 了解Lambda语法 了解方法引用 了解Fucntional与Stream API ...

  9. Java高性能并发编程——线程池

    在通常情况下,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的 ...

  10. 【技巧总结】Penetration Test Engineer[4]-Web-Security(文件处理、会话管理、访问控制、SSRF、反序列化漏洞)

    Web安全基础2 3.8.文件处理 1)文件上传 一个正常的业务需求,问题在于控制上传合法文件. 防御文件上传 客户端javascript校验(通常校验扩展名) 检查MIME类型 检查内容是否合法 随 ...