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与数列的更多相关文章

  1. luogu P5161 WD与数列 SAM 线段树合并 启发式合并

    LINK:WD与数列 这道题可谓妙绝 我明白了一个增量统计的原理. 原本的想法是:差分之后 显然长度为1的单独统计 长度为2的以及更多就是字符串之间的匹配问题了. 对差分序列建立SAM 由于第一个是一 ...

  2. 【LUOGU???】WD与数列 sam 启发式合并

    题目大意 给你一个字符串,求有多少对不相交且相同的子串. 位置不同算多对. \(n\leq 300000\) 题解 先把后缀树建出来. DFS 整棵树,维护当前子树的 right 集合. 合并两个集合 ...

  3. 『题解』LibreOJ6277 数列分块入门 1

    更好的阅读体验 Portal Portal1: LibreOJ Description 给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及区间加法,单点查值. Input 第一行输入一个数字 ...

  4. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  5. 【LGP5161】WD与数列

    题目 也是可以用\(SAM\)来做的 我们发现要求原串不相交,那么就要求在差分序列里不相交并且不相邻 考虑一下\(SAM\),暴力做法自然是对每一个节点统计其所有\(endpos\)的影响 既然这样我 ...

  6. P5161 WD与数列(后缀自动机+线段树合并)

    传送门 没想出来→_→ 首先不难看出要差分之后计算不相交也不相邻的相等子串对数,于是差分之后建SAM,在parent树上用线段树合并维护endpos集合,然后用启发式合并维护一个节点对另一个节点的贡献 ...

  7. hdu4970 Killing Monsters (差分数列)

    2014多校9 1011 http://acm.hdu.edu.cn/showproblem.php?pid=4970 Killing Monsters Time Limit: 2000/1000 M ...

  8. CSP-S考前各种idea题解乱堆

    快要考试了我还是这么菜. 已经没有心思维护我的博客了.开一篇博文吧.可能会记得很乱. 这也许是我OI生涯的最后一篇博文了?? 肯定很长很长. 不可能的.谁知道什么时候我心态恢复就把上面两句话删掉开始在 ...

  9. 2019 第十届蓝桥杯大赛软件类省赛 Java A组 题解

    2019 第十届蓝桥杯大赛软件类省赛 Java A组 试题A 题解 ​ 题目最后一句贴心的提示选手应该使用 long (C/C++ 应该使用 long long). ​ 本题思路很直白,两重循环.外层 ...

  10. 5806 NanoApe Loves Sequence Ⅱ(尺取法)

    传送门 NanoApe Loves Sequence Ⅱ Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K ...

随机推荐

  1. 最好的在线PDF转换工具服务

    工作中有时候会碰到需要转换PDF文件的情况,现在网上就要很多免费的在线工具,可以进行PDF文件的转换,下面就来介绍一些可以直接在浏览器中将文档.电子表格.和图片转换为PDF或者互相转换的服务工具. ​ ...

  2. request to https://registry.npm.taobao.org/cnpm failed, reason: certificate has expired

    换华为的,否则会出问题:cnpm confg set registry https://mirrors.huaweicloud.com/repository/npm/ npm ERR! code CE ...

  3. python-一种字符串排序方式

    最近工作中,需要使用python实现一种排序方式,简要说明如下: 1.排序方式 假设有一个序列,数据为:['n1', 'n2', 'n10', 'n11', 'n21', 'n3', 'n13', ' ...

  4. Mysql 创建索引语句

    mysql有哪些索引 index 普通索引 alter table table_name add index index_name(column) 最基本的索引,没有任何限制 primary key ...

  5. JS注释 JS变量

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  6. SELinux(一) 简介

    首发公号:Rand_cs 前段时间的工作遇到了一些关于 SELinux 的问题,初次接触不熟悉此概念,导致当时配置策略时束手束脚,焦头烂额,为此去系统的学习了下 SELinux 的东西.聊 SELin ...

  7. LINQ to Entities does not recognize the method 'System.String ToString()' method

    LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method ca ...

  8. 使用 OpenTelemetry 构建可观测性 06 - 生态系统

    过去的五篇文章讨论了如何使用 OpenTelemetry 来构建可观测性的技术细节.我认为在本博文系列的结尾介绍有关 OTel 生态系统的信息,为读者提供更全面的了解非常重要.OpenTelemetr ...

  9. django通过channels实现websocket

    WebSocket协议是基于TCP的一种新的协议.WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符.它实现了浏览器与服务器全双工(full-duplex ...

  10. Vue2复习

    Vue2 插值.指令.动态属性.表达式.v-html 插值:{{ data }} 指令 & 动态属性:例子(:id="xxx") 表达式:可以用于赋值,写在{{}}里面 v ...