Description

题库链接

给定一个长度为 \(n\) 的字符串 \(S\) ,令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀。求

\[\sum_{1\leqslant i<j\leqslant n}\text{len}(T_i)+\text{len}(T_j)-2\times\text{lcp}(T_i,T_j)\]

其中, \(\text{len}(a)\) 表示字符串 \(a\) 的长度, \(\text{lcp}(a,b)\) 表示字符串 \(a\) 和字符串 \(b\) 的最长公共前缀。

\(2\leqslant n\leqslant 500000\) ,且均为小写字母。

Solution

注意到原式可化为

\[\begin{aligned}&(n-1)\sum_{i=1}^n\text{len}(T_i)-2\sum_{1\leqslant i<j\leqslant n}\text{lcp}(T_{sa_i},T_{sa_j})\\=&\frac{(n-1)n(n+1)}{2}-2\sum_{1\leqslant i<j\leqslant n}\text{lcp}(T_{sa_i},T_{sa_j})\end{aligned}\]

记 \(\text{LCP}(i,j)=\text{lcp}(T_{sa_i},T_{sa_j})\) ,由于

\[\text{LCP}(i,j)=\min_{i<k\leq j}\text{LCP}(k-1,k)\]

那么就可以单调栈预处理出两个数组 \(l_i,r_i\) 表示左边(右边)第一个大于(大于等于) \(height_i\) 的位置。注意,由于不能重复计算,等于只能一边取。

然后直接算贡献就好了。

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 500000+5; char ch[N];
int n, m, x[N<<1], y[N<<1], c[N], sa[N], rk[N], height[N], l[N], r[N], s[N], top; void get_sa() {
for (int i = 1; i <= n; i++) c[x[i] = ch[i]]++;
for (int i = 2; i <= m; i++) c[i] += c[i-1];
for (int i = n; i >= 1; i--) sa[c[x[i]]--] = i;
for (int k = 1; k <= n; k <<= 1) {
int num = 0;
for (int i = n-k+1; i <= n; i++) y[++num] = i;
for (int i = 1; i <= n; i++) if (sa[i] > k) y[++num] = sa[i]-k;
for (int i = 1; i <= m; i++) c[i] = 0;
for (int i = 1; i <= n; i++) c[x[i]]++;
for (int i = 2; i <= m; i++) c[i] += c[i-1];
for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i];
swap(x, y); x[sa[1]] = num = 1;
for (int i = 2; i <= n; i++)
x[sa[i]] = (y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]) ? num : ++num;
if ((m = num) == n) break;
}
}
void get_height() {
for (int i = 1; i <= n; i++) rk[sa[i]] = i;
for (int i = 1, k = 0; i <= n; i++) {
if (rk[i] == 1) continue;
if (k) --k; int j = sa[rk[i]-1];
while (j+k <= n && i+k <= n && ch[i+k] == ch[j+k]) ++k;
height[rk[i]] = k;
}
}
void work() {
scanf("%s", ch+1), n = strlen(ch+1), m = 'z';
get_sa(); get_height(); ll ans = 1ll*(1+n)*n*(n-1)/2;
s[++top] = n+1;
for (int i = n; i >= 2; i--) {
while (top != 1 && height[i] <= height[s[top]]) --top;
r[i] = s[top]; s[++top] = i;
}
s[top = 1] = 1;
for (int i = 2; i <= n; i++) {
while (top != 1 && height[i] < height[s[top]]) --top;
l[i] = s[top]; s[++top] = i;
}
for (int i = 2; i <= n; i++) ans -= 2ll*(i-l[i])*(r[i]-i)*height[i];
printf("%lld\n", ans);
}
int main() {work(); return 0; }

[AHOI 2013]差异的更多相关文章

  1. [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】

    题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...

  2. BZOJ3238:[AHOI 2013]差异

    求一个字符串的∑ ∑ len[i] + len[j] - 2 * lcp(i, j),其中i,j表示从i,j开始的后缀. 方法一:SA+单调栈,自行yy. 方法二:SAM构造出来,然后每个状态对答案的 ...

  3. BZOJ 3236 AHOI 2013 作业 莫队+树状数组

    BZOJ 3236 AHOI 2013 作业 内存限制:512 MiB 时间限制:10000 ms 标准输入输出     题目类型:传统 评测方式:文本比较 题目大意: 此时己是凌晨两点,刚刚做了Co ...

  4. 【BZOJ 3238】【AHOI 2013】差异

    http://www.lydsy.com/JudgeOnline/problem.php?id=3238 后缀数组裸题但是\(5\times 10^5\)貌似常数有点大就过不了?(我的sa常数那么大想 ...

  5. 【AHOI 2013】差异

    Problem Description 给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀.求 \(\sum_{1\leqslant i&l ...

  6. BZOJ 3236 AHOI 2013 作业 莫队算法

    题目大意:给出一些数,问在一个区间中不同的数值有多少种,和在一个区间中不同的数值有多少个. 思路:因为没有改动,所以就想到了莫队算法.然后我写了5K+的曼哈顿距离最小生成树,然后果断T了.(100s的 ...

  7. 解题:AHOI 2013 作业

    题面 emmm......我把莫队扔到了杂题里,因为感觉局限挺大的=.= 这题是莫队维护信息+分块查询答案,都是两者的基本操作,复杂度$O(m$ $sqrt(n)+n$ $sqrt(m))$ 所以为啥 ...

  8. [ AHOI 2013 ] 作业 & [ BZOJ 3809 ] Gty的二逼妹子序列

    \(\\\) Description 给出一个长为 \(n\) 的数列 \(A\) 和 \(k\),多次询问: 对于一个区间 \([L_i,R_i]\),问区间内有多少个数在 \([a_i,b_i]\ ...

  9. [NOI 2015]品酒大会

    Description 题库链接 \(n\) 杯鸡尾酒排成一行,其中第 \(i\) 杯酒 (\(1 \leq i \leq n\)) 被贴上了一个标签 \(s_i\),每个标签都是 \(26\) 个小 ...

随机推荐

  1. chrome常用小插件

    1.广告终结者                    (去广告) 2.adsafe2.0.1                  (去广告) 3.Infinity New Tab           ( ...

  2. (25)uniGUI for C++ builder之UniHTMLMemo初使用及uniGUI如何调用javaScript

    (25)uniGUI for C++ builder之UniHTMLMemo初使用及uniGUI如何调用javaScript 2018年09月29日 22:58:20 中国银行之路在脚下 阅读数:11 ...

  3. cnn公式推导

    CNN公式推导 1 前言 在看此blog之前,请确保已经看懂我的前两篇blog[深度学习笔记1(卷积神经网络)]和[BP算法与公式推导].并且已经看过文献[1]的论文[Notes on Convolu ...

  4. linux下java版本管理工具jenv使用介绍

    不同的项目使用的java版本不同,每次切换时都需要手动去修改java的环境变量,麻烦至极. jenv可以管理java版本,轻松实现管理多个java的问题. 一.下载jenv $ git clone h ...

  5. Java Listener中Spring接口注入的使用

    在项目中使用Spring通常使用他的依赖注入可以很好的处理,接口与实现类之间的耦合性,但是通常的应用场景中都是Service层和DAO层,或者web层的话, 也是与Strust2来整合,那么如何在Li ...

  6. Windows 出现了回声 & 微软账号无法登陆

    Windows 出现了回声,第一反应是杜比音效偷偷背着我开启了客厅模式(后面看了下并没有这个模式,后话了...). 再我尝试打开它发现提示网络无法连接,于是我就直接卸载了,但回声依能没有解决. 后面我 ...

  7. mybatis 控制台打印执行的SQL语句

    1. Spring boot 集成 mybatis [转载]SpringBoot中Mybatis打印sql 1.1 如果使用的是application.properties文件,加入如下配置: log ...

  8. 设置多台机器linux服务器ssh相互无密码访问

    在每台服务器上都执行ssh-keygen -t rsa生成密钥对: $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter ...

  9. 01-Linux的基本指令

    Linux的基本指令 基础指令(重点) 1.ls指令: 含义:ls(list) 用法1:#ls 含义:列出当前工作目录下的所有文件/文件夹的名称 用法2:#ls  路径 含义:列出指定路径下的所有文件 ...

  10. [0day]微软XP系统右键菜单任意DLL却持

    作者:K8哥哥只要在DLL上右键就被却持 任意DLL名称 任意位置 (其实是EXPLOR) 这个漏洞早已存在,08年的时候就发现了(当时编译某个DLL源码) 在DLL上右键看属性的时候崩溃了,当时就想 ...