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]差异——后缀自动机的更多相关文章

  1. BZOJ3238: [Ahoi2013]差异(后缀自动机)

    题意 题目链接 Sol 前面的可以直接算 然后原串翻转过来,这时候变成了求任意两个前缀的最长公共后缀,显然这个值应该是\(len[lca]\),求出\(siz\)乱搞一下 #include<bi ...

  2. BZOJ 3238: [Ahoi2013]差异 [后缀自动机]

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2512  Solved: 1140[Submit][Status ...

  3. bzoj3238 [Ahoi2013]差异 后缀数组+单调栈

    [bzoj3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Ou ...

  4. [Ahoi2013]差异(后缀自动机)

    /* 前面的那一坨是可以O1计算的 后面那个显然后缀数组单调栈比较好写??? 两个后缀的lcp长度相当于他们在后缀树上的lca的深度 那么我们就能够反向用后缀自动机构造出后缀树然后统计每个点作为lca ...

  5. 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)

    题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...

  6. BZOJ 3238 [Ahoi2013]差异 ——后缀自动机

    后缀自动机的parent树就是反串的后缀树. 所以只需要反向构建出后缀树,就可以乱搞了. #include <cstdio> #include <cstring> #inclu ...

  7. [AHOI2013]差异 后缀自动机_Parent树

    题中要求: $\sum_{1\leqslant i < j \leq n } Len(T_{i}) +Len(T_{j})-2LCP(T_{i},T_{j})$ 公式左边的部分很好求,是一个常量 ...

  8. BZOJ.3238.[AHOI2013]差异(后缀自动机 树形DP/后缀数组 单调栈)

    题目链接 \(Description\) \(Solution\) len(Ti)+len(Tj)可以直接算出来,每个小于n的长度会被计算n-1次. \[\sum_{i=1}^n\sum_{j=i+1 ...

  9. BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

    http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有 ...

随机推荐

  1. 为什么说Objective-C是一门动态的语言?

    object-c类的类型和数据变量的类型都是在运行是确定的,而不是在编译时确定.例如:多态特性,我们可以使用父类对象来指向子类对象,并且可以用来调用子类的方法.运行时(runtime)特性,我们可以动 ...

  2. Linux中java应用程序的部署,使其开机自动启动

    初步需求:将在Windows/MyEclipse中开发的java应用程序部署到Linux服务器上,使其运行 针对需求,可以参考下面这些文章,但是这些文章很多东西没有提及到,我自己尝试部署运行 在lin ...

  3. linux内存

    在Linux的世界中,从大的方面来讲,有两块内存,一块叫做内存空间,Kernel Space,另一块叫做用户空间,即User Space.它们是相互独立的,Kernel对它们的管理方式也完全不同 驱动 ...

  4. 常见bug解析-移动端

    手机测试常见bug解析 1.测试时遇到“手机无响应”? 有以下几个原因: a.手机内存不足 b.android进程之间死锁引起的(就是两个进程之间) c.手机的CPU运行高引起的 可以查看手机的崩溃日 ...

  5. windows下网络命令----Tracert命令详解

    现在网络四通八达,网线光纤基站卫星,只要运营商能收费的地方,就有网络,覆盖了全世界所有的区域.彻底改变了以前通讯基本靠吼的情况.那么宽广的网络世界,超过100米就得需要中继放大信号的网线,即使现在的光 ...

  6. CUDA9.0+tensorflow-gpu1.8.0+Python2.7服务器环境搭建经验

    最近在实验室的服务器上搭建Tensorflow,CUDA是默认的9.0,管理员已经装好了,同时环境变量都已经配好. 直接用Anaconda创建的虚拟环境,使用pip install tensorflo ...

  7. 学习bash——通配符与特殊符号

    一.通配符 这是bash操作环境中一个非常有用的功能,这让我们使用bash处理数据就更方便了. 常用通配符如下: 符号 意义 * 代表0个到无穷多个任意字符 ? 代表一个任意字符 [] 代表一定有一个 ...

  8. 数据结构14——AC自动机

    一.相关介绍 知识要求 字典树Trie KMP算法 AC自动机 多模式串的字符匹配算法(KMP是单模式串的字符匹配算法) 单模式串问题&多模式串问题 单模就是给你一个模式串,问你这个模式串是否 ...

  9. Web-request内置对象在JSP编程中的应用

  10. IO流分类详细介绍和各种字节流类介绍与使用 过滤流 字节流

    Java基础笔记 – IO流分类详细介绍和各种字节流类介绍与使用 过滤流 字节流本文由 arthinking 发表于627 天前 ⁄ Java基础 ⁄ 评论数 1 ⁄ 被围观 2,036 views+ ...