题解 WD与数列
P5161 WD与数列
可以想到原条件是一个差分形式,所以我们对原数组差分。然后发现答案其实就是 \(\sum_{i<j} \min(lcp(i+1,j+1)+1,j-i)\)。
这个东西先跑 SA,然后建笛卡尔树。
考虑对于一个区间,其值为 \(x\)。那么相当于是求 \(\sum_{l\in S,r\in T} \min(|sa_{l}-sa_{r}|,x)\)。
笛卡尔树的一个性质是:较小的区间之和不超过 \(O(n\log n)\)。所以直接暴力枚举较小区间,假设为 \(l\),那么对于右边相当于是求区间内 \(\le\) 某个数的个数,我们显然可以把询问按照 \(x\) 离线下来,从小到大做。或者直接开主席树,都是 \(O(n\log^2n)\) 的。这题略微卡常,注意实现
- 好像存在 \(O(n\log n)\) 的做法。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxt=1e7, maxn=3e5+5;
int n,m;
int sa[maxn], rk[maxn], cnt[maxn], tp[maxn], height[maxn], lg[maxn], w[maxn][20];
int s[maxn], a[maxn];
void basesort(){
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++) cnt[rk[i]]++;
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[rk[tp[i]]]--]=tp[i];
return ;
}
void SuffixSort() {
for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
basesort();
for(int w=1,p=0;p<n;m=p,w<<=1) {
p=0;
for(int i=1;i<=w;i++) tp[++p]=n-w+i;
for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
basesort();
for(int i=1;i<=n;++i) swap(tp[i],rk[i]);
rk[sa[1]]=1;
p=1;
for(int i=2;i<=n;i++) {
if(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w]) rk[sa[i]]=p;
else rk[sa[i]]=++p;
}
}
return ;
}
int lcp(int l,int r) {
int k=lg[r-l];
return min(w[l+1][k],w[r-(1<<k)+1][k]);
}
void init() {
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) s[i]=a[i]-a[i-1];
for(int i=1;i<=n;i++) a[i]=s[i];
sort(a+1,a+n+1); m=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=n;i++) s[i]=lower_bound(a+1,a+m+1,s[i])-a;
SuffixSort();
int k=0;
for(int i=1;i<=n;i++) {
if(k) --k;
int j=sa[rk[i]-1];
while(i+k<=n&&s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;
}
lg[1]=0;
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++) w[i][0]=height[i];
for(int j=1;(1<<j)<=n;j++) {
for(int i=1;i+(1<<j)-1<=n;i++) {
w[i][j]=min(w[i][j-1],w[i+(1<<j-1)][j-1]);
}
}
return ;
}
int tl[maxn], tr[maxn];
int tot;
int ls[maxt], rs[maxt], rt[maxn];
ll sum[maxt], sum2[maxt];
void build(int &x,int l,int r) {
x=++tot;
if(l==r) return ;
int mid=l+r>>1;
build(ls[x],l,mid);
build(rs[x],mid+1,r);
return ;
}
void updata(int &x,int x2,int p,int c,int l,int r) {
x=++tot;
sum[x]=sum[x2]+p*c, sum2[x]=sum2[x2]+c, ls[x]=ls[x2], rs[x]=rs[x2];
if(l==r) return ;
int mid=l+r>>1;
if(p<=mid) updata(ls[x],ls[x2],p,c,l,mid);
else updata(rs[x],rs[x2],p,c,mid+1,r);
return ;
}
pair<ll,ll> operator + (pair<ll,ll> x,pair<ll,ll> y) {
return {x.first+y.first,x.second+y.second};
}
pair<ll,ll> query(int x1,int x2,int L,int R,int l,int r) {
if(L>R) return {0,0};
if(L<=l&&r<=R) return {sum[x2]-sum[x1],sum2[x2]-sum2[x1]};
int mid=l+r>>1;
pair<ll,ll> res={0,0};
if(L<=mid) res=res+query(ls[x1],ls[x2],L,R,l,mid);
if(mid<R) res=res+query(rs[x1],rs[x2],L,R,mid+1,r);
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
init();
vector<int> vec;
for(int i=2;i<=n;i++) {
while(vec.size()&&height[vec.back()]>=height[i]) {
tr[vec.back()]=i;
vec.pop_back();
}
if(vec.size()) tl[i]=vec.back();
else tl[i]=1;
vec.push_back(i);
}
while(vec.size()) tr[vec.back()]=n+1, vec.pop_back();
build(rt[0],1,n);
for(int i=1;i<=n;i++) updata(rt[i],rt[i-1],sa[i],(sa[i]!=1),1,n);
ll ans=0;
for(int i=2;i<=n;i++) {
int l=tl[i], r=tr[i]; --r;
int x=height[i]+1;
if(i-l<=r-i+1) {
for(int j=l;j<i;j++) {
int v=sa[j];
if(v==1) continue;
ll sum=r-i+1-(i<=rk[1]&&rk[1]<=r);
pair<ll,ll> res=query(rt[i-1],rt[r],max(v-x,1),v,1,n);
ans+=res.second*v-res.first, sum-=res.second;
res=query(rt[i-1],rt[r],v+1,min(v+x,n),1,n);
ans+=res.first-res.second*v, sum-=res.second;
ans+=sum*x;
}
}else {
for(int j=i;j<=r;j++) {
int v=sa[j];
if(v==1) continue;
ll sum=i-l-(l<=rk[1]&&rk[1]<i);
pair<ll,ll> res=query(rt[l-1],rt[i-1],max(v-x,1),v,1,n);
ans+=res.second*v-res.first, sum-=res.second;
res=query(rt[l-1],rt[i-1],v+1,min(v+x,n),1,n);
ans+=res.first-res.second*v, sum-=res.second;
ans+=sum*x;
}
}
}
cout<<ans+n-1<<'\n';
return 0;
}
题解 WD与数列的更多相关文章
- luogu P5161 WD与数列 SAM 线段树合并 启发式合并
LINK:WD与数列 这道题可谓妙绝 我明白了一个增量统计的原理. 原本的想法是:差分之后 显然长度为1的单独统计 长度为2的以及更多就是字符串之间的匹配问题了. 对差分序列建立SAM 由于第一个是一 ...
- 【LUOGU???】WD与数列 sam 启发式合并
题目大意 给你一个字符串,求有多少对不相交且相同的子串. 位置不同算多对. \(n\leq 300000\) 题解 先把后缀树建出来. DFS 整棵树,维护当前子树的 right 集合. 合并两个集合 ...
- 『题解』LibreOJ6277 数列分块入门 1
更好的阅读体验 Portal Portal1: LibreOJ Description 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,单点查值. Input 第一行输入一个数字 ...
- [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)
https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...
- 【LGP5161】WD与数列
题目 也是可以用\(SAM\)来做的 我们发现要求原串不相交,那么就要求在差分序列里不相交并且不相邻 考虑一下\(SAM\),暴力做法自然是对每一个节点统计其所有\(endpos\)的影响 既然这样我 ...
- P5161 WD与数列(后缀自动机+线段树合并)
传送门 没想出来→_→ 首先不难看出要差分之后计算不相交也不相邻的相等子串对数,于是差分之后建SAM,在parent树上用线段树合并维护endpos集合,然后用启发式合并维护一个节点对另一个节点的贡献 ...
- hdu4970 Killing Monsters (差分数列)
2014多校9 1011 http://acm.hdu.edu.cn/showproblem.php?pid=4970 Killing Monsters Time Limit: 2000/1000 M ...
- CSP-S考前各种idea题解乱堆
快要考试了我还是这么菜. 已经没有心思维护我的博客了.开一篇博文吧.可能会记得很乱. 这也许是我OI生涯的最后一篇博文了?? 肯定很长很长. 不可能的.谁知道什么时候我心态恢复就把上面两句话删掉开始在 ...
- 2019 第十届蓝桥杯大赛软件类省赛 Java A组 题解
2019 第十届蓝桥杯大赛软件类省赛 Java A组 试题A 题解 题目最后一句贴心的提示选手应该使用 long (C/C++ 应该使用 long long). 本题思路很直白,两重循环.外层 ...
- 5806 NanoApe Loves Sequence Ⅱ(尺取法)
传送门 NanoApe Loves Sequence Ⅱ Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/131072 K ...
随机推荐
- kubernetes命令补全k8s命令补全
echo "source <(kubectl completion bash)" >> ~/.bashrc source <(kubectl complet ...
- 一周万星的文本转语音开源项目「GitHub 热点速览」
上周的热门开源项目让我想起了「图灵测试」,测试者在不知道对面是机器还是人类的前提下随意提问,最后根据对方回复的内容,判断与他们交谈的是人还是计算机.如果无法分辨出回答者是机器还是人类,则说明机器已通过 ...
- numpy基础--通用函数:快速的元素级数组函数
以下代码的前提:import numpy as np 通用函数(即ufunc)是一种对narray中的数组执行元素级运算的函数.可以看作简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量化 ...
- ES备份恢复
1.官网提供snap快照备份恢复 https://www.elastic.co/guide/en/elasticsearch/reference/7.9/snapshot-restore.html 环 ...
- 在.NET Core,除了VB的LikeString,还有其它方法吗?(四种LikeString实现分享)
Like运算符很好用,特别是它所提供的其中*.?这两种通配符,在Windows文件系统和各类项目中运用非常广泛. 但Like运算符仅在VB中支持,在C#中,如何实现呢? 以下是关于LikeString ...
- gradle dependencies 查找jar导入OR解决jar冲突
在gradle项目中,使用gradle dependencies先查询jar包的导入关系.然后找到导入的jar加入到项目中来.解决jar冲突等问题. 类似格式如下: annotationProcess ...
- ThreadLocal 核心源码分析
ThreadLocal 简介 多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程 ...
- Nginx 静态站点配置不对导致301跳转的坑
背景 是这样的,我们前端服务器统一的入口是 kong网关 ,我们还有一个Nginx静态资源站点:static.mysite.com,根配置如下: location / { root /home/web ...
- python 方法调用另一个方法报错,捕获的异常只有message,优化为trackback捕获详细的报错信息
A方法加了try...expect... B方法也加了try....expect... B方法调用了A方法,A方法查找元素,找不到报超时异常,实际B捕获到的异常,只有message\n,没有办法看出是 ...
- 深入理解Spring AOP中的@EnableAspectJAutoProxy
本文分享自华为云社区<Spring高手之路20--深入理解@EnableAspectJAutoProxy的力量>,作者: 砖业洋__. 1. 初始调试代码 面向切面编程(AOP)是一种编程 ...