这个题一看就是为后缀家族设计的

我们看到我们要求的这个柿子

\[\sum_{i=1}^n\sum_{j=i+1}^nT_i+T_j-2\times lcp(T_i,T_j)
\]

显然的是前面的那些东西是个定值

就是保证每一个长度都会被其他长度算到,也就是算到\(n-1\)次

于是把前面那些东西拿出来就是

\[\frac{(n+1)(n-1)n}{2}
\]

之后再看后面那些东西

所有后缀的\(lcp\)的长度?

先来考虑一下如何求两个后缀的\(lcp\)

哈希+二分啊\(SA\)啊

对于后缀\(i,j\),他们的\(lcp\)长度就是\(min(heighht[rk[i]+1]...height[rk[j]])\)

于是现在的问题转化为求出\(height\)数组所有子区间的最小值的和

我们可以考虑一个动态往序列末尾加数的过程

也就是我们往末尾加一个数都会和之前所有的数形成一个新的区间

考虑快速算出这些区间的最小值的和

我们可以对每一个数存储一个\(a_i\),表示\(i\)到当前序列末尾的最小值是多少

我们每次加入一个数可以对更新一下所有的\(a_i\),把所有比当前加入的数大的\(a_i\)变成当前数就好了

这不就\(T\)了吗

我们发现我们只需要求出所有\(a_i\)的和,并不需要关心这个\(i\)来自哪里,于是我们可以把相等的\(a_i\)放在一起计算,也就是每次新加入一个数就暴力扫一遍把那些比当前加入数大的合并到一个\(a_i\)里

看起来复杂度并不科学,但是最坏情况下就相当于是一个线段树的复杂度了,\(O(n)\)的,跑的还挺快的

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 500005
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define pt putchar(1)
inline int read()
{
char c=getchar();int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,top;
LL ans=0,sum=0;
char S[maxn];
int tax[maxn],sa[maxn],rk[maxn],tp[maxn],height[maxn];
int L[maxn],R[maxn],st[maxn];
int a[maxn],cnt[maxn];
LL pre[maxn];
inline void qsort()
{
for(re int i=0;i<=m;i++) tax[i]=0;
for(re int i=1;i<=n;i++) tax[rk[i]]++;
for(re int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(re int i=n;i;--i) sa[tax[rk[tp[i]]]--]=tp[i];
}
int main()
{
scanf("%s",S+1);
n=strlen(S+1);
m=75;
for(re int i=1;i<=n;i++) rk[i]=S[i]-'a'+1,tp[i]=i;
qsort();
for(re int w=1,p=0;p<n;m=p,w<<=1)
{
p=0;
for(re int i=1;i<=w;i++) tp[++p]=n-w+i;
for(re int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
qsort();
for(re int i=1;i<=n;i++) std::swap(tp[i],rk[i]);
rk[sa[1]]=p=1;
for(re int i=2;i<=n;i++) rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
}
int k=0;
for(re int i=1;i<=n;i++)
{
if(k) --k;
int j=sa[rk[i]-1];
while(S[i+k]==S[j+k]) ++k;
height[rk[i]]=k;
}
ans+=height[2];
a[1]=ans;cnt[1]=1,sum=ans;
top=1;
for(re int i=3;i<=n;i++)
{
int now=1;
while(top&&height[i]<=a[top])
now+=cnt[top],sum-=a[top]*cnt[top],top--;
cnt[++top]=now;
a[top]=height[i];
sum+=cnt[top]*a[top];
ans+=sum;
}
printf("%lld\n",(LL)(n-1)*(LL)(n+1)*(LL)n/2ll-2ll*ans);
return 0;
}

【[AHOI2013]差异】的更多相关文章

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

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

  2. bzoj 3238 Ahoi2013 差异

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

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

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

  4. BZOJ_3238_[Ahoi2013]差异_后缀自动机

    BZOJ_3238_[Ahoi2013]差异_后缀自动机 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sam ...

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

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  6. 【LG4248】[AHOI2013]差异

    [LG4248][AHOI2013]差异 题面 洛谷 题解 后缀数组版做法戳我 我们将原串\(reverse\),根据后缀自动机的性质,两个后缀的\(lcp\)一定是我们在反串后两个前缀的\(lca\ ...

  7. 【BZOJ3238】[AHOI2013]差异

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

  8. P4248 [AHOI2013]差异 解题报告

    P4248 [AHOI2013]差异 题目描述 给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀.求 \[\displaystyle \s ...

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

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

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

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

随机推荐

  1. WPF备忘录(3)如何从 Datagrid 中获得单元格的内容与 使用值转换器进行绑定数据的转换IValueConverter

    一.如何从 Datagrid 中获得单元格的内容 DataGrid 属于一种 ItemsControl, 因此,它有 Items 属性并且用ItemContainer 封装它的 items. 但是,W ...

  2. C语言Win32 Application 的标题栏图标,任务栏图标,exe文件图标问题

    我们这里新建的首先是一个空工程,新建c文件. 因为是空工程,我们没有资源文件,要用到图标资源,首先要新建和导入图标为资源. 选择引入资源,选择要引入的ico文件 完成,重命名保存Script_icon ...

  3. 【MongoDB-query查询条件】

    在上一篇中简要使用了C# 对MongoDB进行数据操作,这里补充一些MongoDB query查询条件文档: Query.All("name", "a",&qu ...

  4. SpringMvc+hibernate+easyui简单的权限管理系统

    用户登录:   主界面:   资源管理:   角色管理:   用户管理:   部门管理:   源码在群共享: 189811613  群满了,直接发链接吧链接:http://pan.baidu.com/ ...

  5. LDA(线性判别分析,Python实现)

    源代码: #-*- coding: UTF-8 -*- from numpy import * import numpy def lda(c1,c2): #c1 第一类样本,每行是一个样本 #c2 第 ...

  6. 【转】Java工程师成神之路

    针对本文,博主最近在写<成神之路系列文章> ,分章分节介绍所有知识点.欢迎关注. 一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 h ...

  7. Netty中消除开始的日志消息修改日志级别

    我是使用logback作为日志打印,之前使用slf4j,日志打印不出,就干脆换掉了. 1.首先引入依赖 <dependency> <groupId>ch.qos.logback ...

  8. SpingBoot —— RestTemplate的配置

    背景:最近工作上搭建了一个中间系统,采用了RestTemplate框架调用第三系统restful接口,调用方采用轮询的方式调用本系统的相关接口,期间多次出现堆内存溢出,系统假死,通用java自带的ja ...

  9. 【代码笔记】iOS-MBProgressHUD-Demo

    一,工程图. 二,代码. ViewController.m #import "ViewController.h" #import "MBProgressHUD.h&quo ...

  10. HCTF2018 pwn题复现

    相关文件位置 https://gitee.com/hac425/blog_data/tree/master/hctf2018 the_end 程序功能为,首先 打印出 libc 的地址, 然后可以允许 ...