[洛谷P4248][AHOI2013]差异
题目大意:给一个长度为$n$的字符串,求:
$$
\sum\limits_{1\leqslant i<j\leqslant n}|suf_i|+|suf_j|-2\times lcp(suf_i,suf_j)
$$
题解:建一棵后缀树,这个式子就成了后缀树上所有后缀之间的距离(后缀树可以把字符串反着加入后缀自动机得到的$fail$数组而来),然后有两种做法:
1. 把$\sum\limits_{1\leqslant i<j\leqslant n}|suf_i|+|suf_j|$直接求出来
$$
\begin{align*}
&\sum\limits_{1\leqslant i<j\leqslant n}|suf_i|+|suf_j|\\
=&\sum\limits_{1\leqslant i<j\leqslant n}i+j\\
=&\dfrac{n(n+1)(n-1)} 2
\end{align*}
$$
然后对每个点考虑它作为$lca$的贡献
2. 直接考虑每条边的贡献
卡点:无
C++ Code:(方法一)
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 500010 namespace SAM {
#define N (maxn << 1)
int head[N], cnt;
struct Edge {
int to, nxt;
} e[N];
inline void addedge(int a, int b) {
e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
} int R[N], fail[N], nxt[N][26];
int lst = 1, idx = 1;
int sz[N];
void append(char __ch) {
int ch = __ch - 'a';
int p = lst, np = lst = ++idx;
R[np] = R[p] + 1; sz[np] = 1;
for (; p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = np;
if (!p) fail[np] = 1;
else {
int q = nxt[p][ch];
if (R[q] == R[p] + 1) fail[np] = q;
else {
int nq = ++idx;
std::copy(nxt[q], nxt[q] + 26, nxt[nq]);
fail[nq] = fail[q], R[nq] = R[p] + 1, fail[np] = fail[q] = nq;
for (; p && nxt[p][ch] == q; p = fail[p]) nxt[p][ch] = nq;
}
}
} long long ans;
void dfs(int u) {
long long tmp = 0;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
dfs(v);
tmp += static_cast<long long> (sz[u]) * sz[v];
sz[u] += sz[v];
}
ans += 2 * tmp * R[u];
}
long long work() {
for (int i = 2; i <= idx; i++) addedge(fail[i], i);
dfs(1);
return ans;
}
#undef N
} int n;
char s[maxn];
long long ans;
int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
for (int i = n; i; i--) SAM::append(s[i]);
ans = static_cast<long long> (n - 1) * n * (n + 1) / 2;
ans -= SAM::work();
printf("%lld\n", ans);
return 0;
}
C++ Code:(方法二)
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 500010 long long ans;
int n;
namespace SAM {
#define N (maxn << 1)
int head[N], cnt;
struct Edge {
int to, nxt;
} e[N];
inline void addedge(int a, int b) {
e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
} int R[N], fail[N], nxt[N][26];
int lst = 1, idx = 1;
int sz[N];
void append(char __ch) {
int ch = __ch - 'a';
int p = lst, np = lst = ++idx;
R[np] = R[p] + 1; sz[np] = 1;
for (; p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = np;
if (!p) fail[np] = 1;
else {
int q = nxt[p][ch];
if (R[q] == R[p] + 1) fail[np] = q;
else {
int nq = ++idx;
std::copy(nxt[q], nxt[q] + 26, nxt[nq]);
fail[nq] = fail[q], R[nq] = R[p] + 1, fail[np] = fail[q] = nq;
for (; p && nxt[p][ch] == q; p = fail[p]) nxt[p][ch] = nq;
}
}
} void dfs(int u) {
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
dfs(v);
sz[u] += sz[v];
ans += static_cast<long long> (n - sz[v]) * (sz[v]) * (R[v] - R[u]);
}
}
void work() {
for (int i = 2; i <= idx; i++) addedge(fail[i], i);
dfs(1);
}
#undef N
} char s[maxn];
int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
for (int i = n; i; i--) SAM::append(s[i]);
SAM::work();
printf("%lld\n", ans);
return 0;
}
[洛谷P4248][AHOI2013]差异的更多相关文章
- 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)
题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...
- 洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)
补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); ...
- 洛谷 P4248: bzoj 3238: [AHOI2013]差异
题目传送门:洛谷 P4248. 题意简述: 定义两个字符串 \(S\) 和 \(T\) 的差异 \(\operatorname{diff}(S,T)\) 为这两个串的长度之和减去两倍的这两个串的最长公 ...
- P4248 [AHOI2013]差异 解题报告
P4248 [AHOI2013]差异 题目描述 给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀.求 \[\displaystyle \s ...
- luogu P4248 [AHOI2013]差异 SAM
luogu P4248 [AHOI2013]差异 链接 luogu 思路 \(\sum\limits_{1<=i<j<=n}{{len}(T_i)+{len}(T_j)-2*{lcp ...
- 线段树分治初步学习&洛谷P5227[AHOI2013]连通图
线段树分治 其实思想说起来是比较简单的,我们把这个题里的所有操作(比如连边删边查询balabala)全部拍到一棵线段树上,然后对着整棵树dfs一下求解答案,顺便把操作做一下,回溯的时候撤销一下即可.虽 ...
- bzoj 3236: 洛谷 P4396: [AHOI2013]作业 (莫队, 分块)
题目传送门:洛谷P4396. 题意简述: 给定一个长度为\(n\)的数列.有\(m\)次询问,每次询问区间\([l,r]\)中数值在\([a,b]\)之间的数的个数,和数值在\([a,b]\)之间的不 ...
- 洛谷 P4248 / loj 2377 [AHOI2013] 差异 题解【后缀自动机】【树形DP】
可能是一个 SAM 常用技巧?感觉 SAM 的基础题好多啊.. 题目描述 给定一个长度为 \(n\) 的字符串 \(S\) ,令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀,求: \[ ...
- 【洛谷 P4248】 [AHOI2013]差异(后缀自动机)
题目链接 \[ans=\sum_{1<=i<j<=n}len(T_i)+len(T_j)-2*lcp(T_i,T_j)\] 观察这个式子可以发现,前面两个\(len\)是常数,后面的 ...
随机推荐
- div仿textarea可输入
原本要用textarea,但是后来发现好像只有IE支持textarea里边使用html标签,由于需要在textarea中显示一条横线(<hr />),在网上查了很久,都说textarea是 ...
- android学习十三 首选项
1,首选项可用用来持久保存用户设置,游戏最高分等 2,首选项有,列表首选项,复选框首选项,对话框首选项.. 3,通过xml文件和代码创建首选项 addPreferencesFromResou ...
- iOS 测试工具reveal可视化调试工具的使用
简单翻译一下reveal可视化图形工具插入项目的官方文档(官方英文版file:///Applications/Reveal.app/Contents/SharedSupport/Documentati ...
- javaweb(四)——Http协议(请求头,响应头详解)
一.什么是HTTP协议 HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的 ...
- C# 简单工厂
如下: public static IList<T> Create<T>(Type type) { if (type == typeof(List<T>)) { r ...
- PS 证件照换颜色
1.打开要修改的图片,然后先Ctrl+J备份一份 2.点击魔法棒,点击要换颜色的地方,如衣服,之后会出现虚线,如果自动选择的不全,可以按住Shift键自行选择区域 3.然后Shift+Fn+F5(由于 ...
- WebDriver--定位元素的8种方式
在UI层面的自动化测试开发中,元素的定位与操作是基础,也是经常遇到的困难所在.webdriver提供了8种定位: 1. id定位:find_element_by_id("id值") ...
- centos7下搭建django
安装环境:centos7.4 1 安装nginx yum install nginx 注:尝试过在本地和腾讯云上安装,使用同一条命令:在本地安装提示没有可用安装包,云上安装正常 启动nginx,并启用 ...
- DNA序列 (DNA Consensus String,ACM/ICPC Seoul 2006,UVa1368
题目描述:算法竞赛入门经典习题3-7 题目思路:每列出现最多的距离即最短 #include <stdio.h> #include <string.h> int main(int ...
- Microservices with Spring Boot
找到一套比较不错的Spring Boot/Cloud入门教程,推荐一下. https://dzone.com/users/1041459/ranga_pec.html