BZOJ 3238 差异

看这个式子其实就是求任意两个后缀的 $ LCP $ 长度和。前面的 $ len(T_i)+len(T_j) $ 求和其实就是 $ n(n-1)(n+1)/2 $ ,这个是很好推的。。

任意两个后缀的 $ LCP $ 长度和很容易想到构造 height 数组,然后问题就变成了所有区间的最小值的和。

这是个套路题,可以单调栈,但是其实分治也很好写!

设我们要求的区间是 $ [l,r] $ 我们可以找出其中最小值所在的位置,这个可以ST表快速求,然后从这个位置进行分治。

这样的分治每进行一次,总有效的元素数量会减少1,因此复杂度是 $ O(nlogn) $ 的。

开始有个地方漏了 1ll 。。。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 500006
#define C 130
namespace wtf {
char ch[MAXN];
int sa[MAXN], tp[MAXN], rnk[MAXN], buc[MAXN], len;
int P[MAXN][20], ht[MAXN]; int que(int l, int r) {
int L = (31 - __builtin_clz(r - l + 1));
return (ht[P[l][L]] < ht[P[r - (1 << L) + 1][L]] ? P[l][L] : P[r - (1 << L) + 1][L]);
} void init() {
len = strlen(ch + 1);
int m = C;
for (int i = 1; i <= len; ++i) ++buc[rnk[i] = ch[i]];
for (int i = 1; i <= m; ++i) buc[i] += buc[i - 1];
for (int i = len; i >= 1; --i) sa[buc[rnk[i]]--] = i;
for (int k = 1, p = 0; p < len; k <<= 1) {
p = 0;
for (int i = 0; i <= m; ++i) buc[i] = 0;
for (int i = len - k + 1; i <= len; ++i) tp[++p] = i;
for (int i = 1; i <= len; ++i) if (sa[i] > k) tp[++p] = sa[i] - k;
for (int i = 1; i <= len; ++i) ++buc[rnk[i]];
for (int i = 1; i <= m; ++i) buc[i] += buc[i - 1];
for (int i = len; i >= 1; --i) sa[buc[rnk[tp[i]]]--] = tp[i];
p = 1;
swap(rnk, tp);
rnk[sa[1]] = 1;
for (int i = 2; i <= len; ++i)
rnk[sa[i]] = (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + k] == tp[sa[i - 1] + k]) ? p : ++p;
m = p;
}
for (int i = 1; i <= len; ++i) rnk[sa[i]] = i;
for (int i = 1, k = 0; i <= len; ++i) {
if (k) --k;
while (ch[i + k] == ch[sa[rnk[i] - 1] + k]) ++k;
ht[rnk[i]] = k;
P[i][0] = i;
}
ht[0] = 0x3f3f3f3f;
for (int i = 1; i < 20; ++i)
for (int j = 1; j <= len - (1 << i) + 1; ++j)
P[j][i] = (ht[P[j][i - 1]] < ht[P[j + (1 << i - 1)][i - 1]] ? P[j][i - 1] : P[j + (1 << i - 1)][i - 1]); } long long res = 0; void div(int l, int r) {
if( l > r ) return;
int ps = que( l , r );
res += 1ll * ht[ps] * ( ps - l + 1 ) * ( r - ps + 1 );
div( l , ps - 1 ) , div( ps + 1 , r );
} void main() {
// freopen("1.in","r",stdin);
scanf("%s", ch + 1);
init();
div( 1 , len );
cout << 1ll * ( len - 1 ) * ( len + 1 ) * len / 2 - 2 * res << endl;
}
}
int main() {
wtf::main();
}

BZOJ 3238 差异的更多相关文章

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

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

  2. BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]

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

  3. bzoj 3238 Ahoi2013 差异

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

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

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

  5. 【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3047  Solved: 1375 Description In ...

  6. bzoj 3238: [Ahoi2013]差异 -- 后缀数组

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 一行,一个字符串S Output 一行,一个 ...

  7. ●BZOJ 3238 [Ahoi2013]差异

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3238 题解: 后缀数组套路深. 问题转化为求出任意两个后缀的LCP之和 在计算贡献时,各种不 ...

  8. 洛谷 P4248: bzoj 3238: [AHOI2013]差异

    题目传送门:洛谷 P4248. 题意简述: 定义两个字符串 \(S\) 和 \(T\) 的差异 \(\operatorname{diff}(S,T)\) 为这两个串的长度之和减去两倍的这两个串的最长公 ...

  9. BZOJ 3238 [Ahoi2013]差异(后缀自动机)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个串,设T[i]表示从第i位开始的后缀, 求sum(len( ...

随机推荐

  1. MacOS安装使用Kettle

    一.环境说明 操作系统版本:macOS Big Sur 11.6.1 机型:Intel版本 JDK版本:Amazon Corretto-openjdk8 Kettle版本:Kettle8.9 二.问题 ...

  2. 寻找写代码感觉(八)之SpringBoot过滤器的使用

    一.什么是过滤器? 过滤器是对数据进行过滤,预处理过程,当我们访问网站时,有时候会发布一些敏感信息,发完以后有的会用*替代,还有就是登陆权限控制等,一个资源,没有经过授权,肯定是不能让用户随便访问的, ...

  3. 【二食堂】Beta - 发布声明

    Beta - 发布声明 新功能 在Beta阶段,图谱方面的新功能有:自定义关系的添加与删除.实体查找.实体名称的修改.实体之间关系的修改.新增了项目创建与删除功能,此外还增加了好友系统,可以实现好友的 ...

  4. camera HSYNC:VSYNC

    HSYNC:行锁存,换行信号VSYNC:祯锁存,换页信号 320×240的屏,每一行需要输入320个脉冲来依次移位.锁存进一行的数据,然后来个HSYNC 脉冲换一行:这样依次输入240行之后换行同时来 ...

  5. Linux C 数据结构 ->单向链表

    之前看到一篇单向链表的博文,代码也看着很舒服,于是乎记录下来,留给自己~,循序渐进,慢慢 延伸到真正的内核链表~(敢问路在何方?路在脚下~) 1. 简介 链表是Linux 内核中最简单,最普通的数据结 ...

  6. Machine learning(3-Linear Algebra Review )

    1.Matrices and vectors Matrix :Rectangular array of numbers a notation R3×3 Vector : An n×1 matrix t ...

  7. STM32程序异常——中断处理要谨慎

    问题背景 最近有一个新项目(车载项目),板子上除了原来的ARM + STM32F030K6Tx又多了一个8bit的mcu的单片机,这可真是嵌入式全家福了. 系统的主要核心工作是由arm来完成,但是在开 ...

  8. Python之模块导入(不看会后悔系列)

    看到这个标题猜想大家内心OS: 什么辣鸡水文,划走划走~ 别急有干货! 静态导入(照顾新人) 假设现在有两个文件a,b在不同目录,b文件想引用a文件中的函数: # test_module/sub_mo ...

  9. Kali-Linux 2020如何设置中文

    话不多说,直接上步骤 首先,想要修改系统默认语言普通用户是办不到的,这个时候就需要切换为root用户在终端输入 sudo su(切换用户指令,后面不加用户名就默认切换为root) 输入管理员密码后就像 ...

  10. NodeJs创建一个简单的服务器

    步骤: 1 //模块化引入 2 let http = require ("http"); 3 4 //创建服务器 5 http.createServer(function(requ ...