[bzoj3238][Ahoi2013]差异——后缀自动机
Brief Description

Algorithm Design
下面给出后缀自动机的一个性质:
两个子串的最长公共后缀,位于这两个串对应的状态在parent树上的lca状态上。并且最长公共后缀的长度就是lca状态的len。
证明:对于一个串,他的所有祖先节点都是他的后缀,并且深度越大,长度越长,由此不难说明两个子串的最长公共后缀一定在lca状态上。考察这个lca,他代表的所有子串一定都是两个子串的公共后缀,我们直接取最大的就可以了。
有了这个性质,我们就可以开始乱搞了。
Code
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
const ll maxn = 500100 << 1;
char s[maxn], str[maxn];
ll head[maxn], f[maxn];
ll ans;
ll n, cnt = 1;
struct edge {
ll to, next;
} e[maxn];
void add_edge(ll u, ll v) {
e[++cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt;
}
struct Suffix_Automaton {
ll fa[maxn], trans[maxn][26], len[maxn], right[maxn];
ll last, root, sz;
bool flag[maxn];
void init() {
memset(flag, 0, sizeof(flag));
sz = 0;
last = root = ++sz;
}
void insert(ll x) {
ll p = last, np = last = ++sz;
len[np] = len[p] + 1;
flag[np] = 1;
right[np] = right[p] + 1;
for (; !trans[p][x]; p = fa[p])
trans[p][x] = np;
if (p == 0)
fa[np] = root;
else {
ll q = trans[p][x];
if (len[q] == len[p] + 1) {
fa[np] = q;
} else {
ll nq = ++sz;
fa[nq] = fa[q];
memcpy(trans[nq], trans[q], sizeof(trans[q]));
len[nq] = len[p] + 1;
fa[q] = fa[np] = nq;
for (; trans[p][x] == q; p = fa[p])
trans[p][x] = nq;
}
}
}
void pre() {
for (ll i = 1; i <= sz; i++) {
if (fa[i])
add_edge(fa[i], i);
}
}
void print() {
for (ll i = 1; i <= sz; i++) {
printf("%3lld ", i);
}
printf("\n");
for (ll i = 1; i <= sz; i++) {
printf("%3lld ", len[i]);
}
printf("\n");
for (ll i = 1; i <= sz; i++)
if (flag[i]) {
printf("%lld:", i);
for (ll j = 1; j <= len[i]; j++)
printf("%c", str[right[i] - (len[i] - j + 1) + 1]);
printf("\n");
}
printf("\n");
}
} sam;
void dfs(ll x) {
ll ct = 0;
f[x] = sam.flag[x] ? 1 : 0;
for (ll i = head[x]; i; i = e[i].next) {
dfs(e[i].to);
ans -= 1ll * 2 * (1ll * f[e[i].to] * ct) * (sam.len[x]);
ct += f[e[i].to];
}
if (f[x] == 1) {
ans -= 1ll * 2 * (1ll * ct) * (sam.len[x]);
}
f[x] += ct;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input", "r", stdin);
#endif
scanf("%s", s + 1);
n = strlen(s + 1);
sam.init();
for (ll i = 1; i <= n; i++) {
ans += (n * i) - i * i + ((n * n - i * i + n - i) >> 1);
str[i] = s[n - i + 1];
}
for (ll i = 1; i <= n; i++)
sam.insert(str[i] - 'a');
sam.pre();
// sam.print();
// printf("%lld\n", ans);
dfs(sam.root);
printf("%lld\n", ans);
}
[bzoj3238][Ahoi2013]差异——后缀自动机的更多相关文章
- BZOJ3238: [Ahoi2013]差异(后缀自动机)
题意 题目链接 Sol 前面的可以直接算 然后原串翻转过来,这时候变成了求任意两个前缀的最长公共后缀,显然这个值应该是\(len[lca]\),求出\(siz\)乱搞一下 #include<bi ...
- BZOJ 3238: [Ahoi2013]差异 [后缀自动机]
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2512 Solved: 1140[Submit][Status ...
- bzoj3238 [Ahoi2013]差异 后缀数组+单调栈
[bzoj3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Ou ...
- [Ahoi2013]差异(后缀自动机)
/* 前面的那一坨是可以O1计算的 后面那个显然后缀数组单调栈比较好写??? 两个后缀的lcp长度相当于他们在后缀树上的lca的深度 那么我们就能够反向用后缀自动机构造出后缀树然后统计每个点作为lca ...
- 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)
题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...
- BZOJ 3238 [Ahoi2013]差异 ——后缀自动机
后缀自动机的parent树就是反串的后缀树. 所以只需要反向构建出后缀树,就可以乱搞了. #include <cstdio> #include <cstring> #inclu ...
- [AHOI2013]差异 后缀自动机_Parent树
题中要求: $\sum_{1\leqslant i < j \leq n } Len(T_{i}) +Len(T_{j})-2LCP(T_{i},T_{j})$ 公式左边的部分很好求,是一个常量 ...
- BZOJ.3238.[AHOI2013]差异(后缀自动机 树形DP/后缀数组 单调栈)
题目链接 \(Description\) \(Solution\) len(Ti)+len(Tj)可以直接算出来,每个小于n的长度会被计算n-1次. \[\sum_{i=1}^n\sum_{j=i+1 ...
- BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp
http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有 ...
随机推荐
- 第一篇 Python安装与环境变量的配置
开发语言有很多种,为什么选Python? 先对各种开发语言做个初识和分类如下:高级语言:Python Java.PHP C# Go ruby C++... ---> 字节码低级语言:C.汇编 - ...
- SQL - SELECT COUNT用法
SQL Server数据库 COUNT() 函数返回匹配指定条件的行数. 语法 SQL COUNT(column_name) 语法 COUNT(column_name) 函数返回指定列 ...
- LeetCode - 3. Longest Substring Without Repeating Characters(388ms)
Given a string, find the length of the longest substring without repeating characters. Examples: Giv ...
- 测试理论--branch testing and boundary testing
1 branch testing 分支测试 测试代码的所有分支 2 boundary testing 测试 程序的限制条件
- 预处理器&预处理变量&头文件保护&条件编译
[常见的预处理功能] #include 头文件保护符 条件编译 [预处理器] 编译之前执行的一段程序,可以部分地改变我们所写的程序 举个例子:当预处理器看到#include标记时就会用指定的头文件的内 ...
- JavaSE复习(二)集合
Collection List(存取有序,有索引,可以重复) ArrayList 底层是数组实现的,线程不安全,查找和修改快,增和删比较慢 LinkedList 底层是链表实现的,线程不安全,增和删比 ...
- mysql数据库,编码错误解决
在写代码的过程中,经常会遇见,将中文字符输入到mysql数据库中,但是查看的时候,却发现,中文显示为乱码的情况,让人相当的头疼,今天正好解决了一个这样遇到的问题,所以简单总结一下: 1.首先查看数据库 ...
- video on web
一.video容器 你可能经常看到.avi或.mp4的视频文件,实际上avi或者mp4只是一种视频容器.打个比方,ZIP的压缩文件可以包含各种各样的文件,同理,视频容器也定义用来怎么存放各种 ...
- Python-爬取"我去图书馆"座位编码
原文地址:http://fanjiajia.cn/2018/11/22/Python-%E7%88%AC%E5%8F%96%E2%80%9D%E6%88%91%E5%8E%BB%E5%9B%BE%E4 ...
- System and Device power management.
Advanced Configuration and Power Management Interface(ACPI)是由Intel,Microsoft等厂家订的一套Spec,规范了OS,APP对于电 ...