题目链接

思路

观察题目中的式子,可以发现前两项是定值。所以只需要求出最后一项就行了。

然后题目就转化为了求字符串中所有后缀的\(lcp\)长度之和。

可以想到用后缀数组。在后缀数组上两个后缀的\(lcp\)长度表现为两个后缀排名之间的\(height\)的最小值。

所以现在问题就又转化为了在\(height\)数组上求所有区间最小值之和。

这个可以用单调栈做到。

代码

/*
* @Author: wxyww
* @Date: 2019-01-30 19:14:49
* @Last Modified time: 2019-01-30 20:49:38
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<bitset>
using namespace std;
typedef long long ll;
#define int ll
const int N = 500010;
ll read() {
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int sa[N],rk[N],height[N],c[N],x[N],y[N];
char s[N];
int m,n;
void get_sa() {
for(int i = 1;i <= m;++i) c[i] = 0;
for(int i = 1;i <= n;++i) ++c[x[i] = s[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 = 2;i <= m;++i) c[i] = 0;
for(int i = 1;i <= n;++i) ++c[x[i]];
for(int i = 1;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);
num = 0;
x[sa[1]] = ++num;
for(int i = 2;i <= n;++i) {
if(y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) x[sa[i]] = num;
else x[sa[i]] = ++num;
}
if(num == n) break;
m = num;
}
}
int h[N],q[N],tail;
void get_height() {
for(int i = 1;i <= n;++i) rk[sa[i]] = i;
int k = 0;
for(int i = 1;i <= n;++i) {
if(rk[i] == 1) continue;
if(k) --k;
int j = sa[rk[i] - 1];
while(j + k <= n && i + k <= n && s[j + k] == s[i + k]) ++k;
h[i] = height[rk[i]] = k;
}
}
ll work() {
int tail = 0;
ll now = 0,ans = 0;
for(int i = 1; i <= n;++i) {
while(height[i] < height[q[tail]] && tail) now -= height[q[tail]] * (q[tail] - q[tail - 1]),tail--;
q[++tail] = i;
now += height[i] * (q[tail] - q[tail - 1]);
ans += now;
}
return ans;
}
int get(int x,int y) {
int ans = 1e9;
int l = min(rk[x],rk[y]),r = max(rk[x],rk[y]);
for(int i = l + 1;i <= r;++i) ans = min(ans,height[i]);
return ans;
}
signed main() {
scanf("%s",s + 1);
n = strlen(s + 1);
m = 'z';
get_sa();
get_height(); ll ans = 0;
for(int i = 1;i <= n;++i)
ans += i * (i - 1) + i * (n - i);
ll LC = 2ll * work();
cout<<ans - LC;
return 0;
}

bzoj3238 差异的更多相关文章

  1. [bzoj3238]差异(后缀数组+单调栈)

    显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去.所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的. 接下来问题就是 ...

  2. 【BZOJ3238】差异(后缀自动机)

    [BZOJ3238]差异(后缀自动机) 题面 BZOJ 题解 前面的东西直接暴力算就行了 其实没必要算的正正好 为了方便的后面的计算 我们不考虑\(i,j\)的顺序问题 也就是先求出\(\sum_{i ...

  3. 【BZOJ3238】[AHOI2013]差异

    [BZOJ3238][AHOI2013]差异 题面 给定字符串\(S\),令\(T_i\)表示以它从第\(i\)个字符开始的后缀.求 \[ \sum_{1\leq i<j\leq n}len(T ...

  4. 【BZOJ3238】[Ahoi2013]差异 后缀数组+单调栈

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

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

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

  6. [bzoj3238][Ahoi2013]差异_后缀数组_单调栈

    差异 bzoj-3238 Ahoi-2013 题目大意:求任意两个后缀之间的$LCP$的和. 注释:$1\le length \le 5\cdot 10^5$. 想法: 两个后缀之间的$LCP$和显然 ...

  7. BZOJ3238 [Ahoi2013]差异 【SAM or SA】

    BZOJ3238 [Ahoi2013]差异 给定一个串,问其任意两个后缀的最长公共前缀长度的和 1.又是后缀,又是\(lcp\),很显然直接拿\(SA\)的\(height\)数组搞就好了,配合一下单 ...

  8. 【BZOJ-3238】差异 后缀数组 + 单调栈

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

  9. 【bzoj3238】 Ahoi2013—差异

    http://www.lydsy.com/JudgeOnline/problem.php?id=3238 (题目链接) 题意 给出一个字符串,求${\sum_{1<=i<j<=n} ...

随机推荐

  1. day 7-2 multiprocessing开启多进程

    一. multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu\_count\(\)查看),在python中大部分情况需要使用多 ...

  2. Day5-1 面向对象和面向过程

    摘要: 类的定义 类的增删改查 对象的增删改查 对象的查找和绑定 面向对象和面向过程的区别: 1.面向过程就像是工厂的流水线,按部就班的有序的工作. 优点:把复杂的问题简单化 缺点:可扩展性差.一个步 ...

  3. Day 4-2 time & datetime模块

    time模块. import time time.time() #输出: 1523195163.140625 time.localtime() # 获取的是操作系统的时间,可以添加一个时间戳参数 # ...

  4. Eclipse导入工程后出现中文乱码

    Eclipse之所以会出现乱码问题是因为eclipse编辑器选择的编码规则是可变的.一般默认都是UTF-8或者GBK,当从外部导入的一个工程时,如果该工程的编码方式与eclipse中设置的编码方式不同 ...

  5. linux audit审计(7)--读懂audit日志

    让我们先来构造一条audit日志.在home目录下新建一个目录,然后配置一条audit规则,对这个目录的wrax,都记录审计日志: auditctl -w /home/audit_test -p wr ...

  6. SharePoint 2013 使用 RBS 功能将二进制大型对象 BLOB 存储在内容数据库外部。

    为每个内容数据库设置 BLOB 存储   启用并配置 FILESTREAM 之后,请按照以下过程在文件系统中设置 BLOB 存储.必须为要对其使用 RBS 的每个内容数据库设置 BLOB 存储. 设置 ...

  7. sklearn训练感知器用iris数据集

    简化版代码 from sklearn import datasets import numpy as np #获取data和类标 iris = datasets.load_iris() X = iri ...

  8. BZOJ2434 [NOI2011] 阿狸的打字机 【树链剖分】【线段树】【fail树】【AC自动机】

    题目分析: 画一下fail树,就会发现就是x的子树中属于y路径的,把y剖分一下,用线段树处理 $O(n*log^2 n)$. 代码: #include<bits/stdc++.h> usi ...

  9. python打印log重复问题

    本博客转载于:http://www.cnblogs.com/huang-yc/p/9209096.html,写得真不错 浅析python日志重复输出问题 目录 问题起源: 问题解析 解决办法 1.改名 ...

  10. mysql查询同一个字段下,不同内容的语句

    太久没有用SQL语句都有些忘记了,今天工作中遇到了那就尝试记录一下吧 需求是这样的:想查询同一个字段下,两条指定了不同内容,的其他的值 主要是要想到用where......in 语句如下:select ...