Atcoder Grand Contest 023 E - Inversions(线段树+扫描线)
毒瘤 jxd 作业……
首先我们不能直接对所有排列计算贡献对吧,这样复杂度肯定吃不消,因此我们考虑对每两个位置 \(x,y(x<y)\),计算 \(p_x>p_y\) 的排列个数。如何计算呢?我们考虑先求出对于一个固定的 \(a_1,a_2,\cdots,a_n\),如何求出满足 \(p_i\le a_i\) 的排列 \(p\) 的个数,我们考虑将一个 \(a_i\) 看作一个限制,那么我们可以想到将这些限制从小到大排序并按照这样的顺序钦定每个元素的取值。那么当我们钦定某个 \(a_i\) 的限制对应的 \(p_i\) 的取值时,所有满足 \(a_j\le a_i\) 的限制 \(j\) 对应的 \(p_j\) 肯定已经被钦定过了,并且 \(p_j\le a_i\),也就是说假设 \(a_i\) 是第 \(x\) 个被钦定的,那么钦定到 \(i\) 时还有 \(a_i-(x-1)\) 个空位可以选择。因此设 \(b_{1},b_2,\cdots,b_n\) 为 \(a\) 数组排序后的结果,那么
\]
我们考虑从这个性质入手计算符合要求的排列个数。对于一对 \((i,j)(i<j)\),如果 \(a_i<a_j\),那么我们就计算 \(p_i>p_j\) 的排列个数,不难发现如果我们固定住了 \(p_i=x\),那么这个限制相当于要求 \(p_j\le x-1\),这个统计起来略有点困难,不过可以注意到,如果我们将 \(a_j\) 的限制变得跟 \(a_i\) 相同,即我们强制规定 \(p_j\le a_i\)。那么对于任意一个满足 \(p_i<p_j\) 的排列 \(p\),通过交换 \(p_i,p_j\) 我们总能够得到一个 \(p_i>p_j\),且符合以上限制的排列,对于 \(p_i<p_j\) 的情况也同理,因此我们可以考虑计算出符合题目原来的条件,且满足 \(p_j\le a_i\) 的排列个数,并将这个值除以二即可得到 \(p_i>p_j\) 的排列个数。考虑如何求出这个东西,我们假设 \(a_i\) 在排好序的数列 \(b\) 中是 \(r_i\) 名,即 \(a_i=b_{r_i}\),那么不难发现如果我们将 \(j\) 上界调至 \(a_i\),会使得 \(j\) 排名变为 \(r_i+1\),并且使原来排名在 \(r_i+1\sim r_j-1\) 中的数的排名提升一格,即
\]
考虑怎样求解这个东西,我们按照排名 \(r_i\) 从小到大枚举 \(a_i\),即按照 \(b_1,b_2,\cdots,b_n\) 的顺序枚举这些限制,在访问过程中可以维护一个序列 \(c\),当我们访问到一个 \(i\) 时就令 \(c_i=b_i-i\),然后每次访问完 \(i\) 就将 \(c_1,c_2,\cdots,c_{i-1}\) 全部乘上 \(\dfrac{b_i-i}{b_i-i+1}\),那么可以发现,如果我们记 \(N(x,y)\) 表示当 \(r_i=x,r_j=y\) 时上式中 \(C’\) 的值,那么 \(N(x,y)\) 就等于,我们访问到 \(x\) 时,\(C·\dfrac{1}{b_y-y+1}·c_x\) 的值。故设 \(p_i\) 满足 \(p_{r_i}=i\),那么访问到 \(y\) 时的贡献就是 \(\prod\limits_{p_x<p_y}N(x,y)=C·\dfrac{1}{b_y-y+1}·\sum\limits_{p_x<p_y}c_x\),这个可以通过维护一个全局乘+单点更新+区间求和的线段树解决。
当然这仅仅只是 \(a_i<a_j\) 的 \((i,j)\) 的贡献。对于 \(a_i\ge a_j\) 的情况也大同小异,我们考虑拿总排列数 \(C\) 减去 \(p_i<p_j\) 的排列个数,后者只需把序列翻转过来再做一遍上述操作即可。
时间复杂度 \(n\log n\)。
注:以下代码中 \(a_i\ge a_j\) 部分的处理方法与题解略有差异,它并没有按照题解所述将序列翻转过来重复 \(a_i<a_j\) 部分的过程,而是在第一遍扫描线过程中一并算出 \(a_i\ge a_j\) 的答案。
const int MAXN=2e5;
const int MOD=1e9+7;
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int n;
struct data{
int val,id;
data(int _val=0,int _id=0):val(_val),id(_id){}
bool operator <(const data &rhs){return val<rhs.val;}
} a[MAXN+5];
struct node{int l,r,val,lz;} s[MAXN*4+5];
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;s[k].lz=1;if(l==r) return s[k].val=0,void();
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void pushdown(int k){
if(s[k].lz^1){
s[k<<1].val=1ll*s[k<<1].val*s[k].lz%MOD;
s[k<<1].lz=1ll*s[k<<1].lz*s[k].lz%MOD;
s[k<<1|1].val=1ll*s[k<<1|1].val*s[k].lz%MOD;
s[k<<1|1].lz=1ll*s[k<<1|1].lz*s[k].lz%MOD;
s[k].lz=1;
}
}
void tag_mul(int x){
s[1].lz=1ll*s[1].lz*x%MOD;
s[1].val=1ll*s[1].val*x%MOD;
}
int query(int k,int l,int r){
if(l>r) return 0;
if(l<=s[k].l&&s[k].r<=r) return s[k].val;
pushdown(k);int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r))%MOD;
}
void modify(int k,int p,int x){
if(s[k].l==s[k].r) return s[k].val=x,void();
pushdown(k);int mid=s[k].l+s[k].r>>1;
(p<=mid)?modify(k<<1,p,x):modify(k<<1|1,p,x);
s[k].val=(s[k<<1].val+s[k<<1|1].val)%MOD;
}
int t[MAXN+5];
void add(int x,int v){for(int i=x;i;i&=(i-1)) t[i]+=v;}
int query(int x){int ret=0;for(int i=x;i<=n;i+=(i&(-i))) ret+=t[i];return ret;}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i].val),a[i].id=i;
sort(a+1,a+n+1);int tot=1,res=0;
for(int i=1;i<=n;i++) tot=1ll*tot*(a[i].val-i+1)%MOD;
if(!tot) return puts("0"),0;build(1,1,n);
for(int i=1;i<=n;i++){
res=(res+1ll*qpow(2*(a[i].val-i+1),MOD-2)*query(1,1,a[i].id-1))%MOD;
res=(0ll+res+query(a[i].id)-1ll*qpow(2*(a[i].val-i+1),MOD-2)*query(1,a[i].id+1,n)%MOD+MOD)%MOD;
tag_mul(1ll*(a[i].val-i)*qpow(a[i].val-i+1,MOD-2)%MOD);
modify(1,a[i].id,a[i].val-i);add(a[i].id,1);
} printf("%d\n",1ll*res*tot%MOD);
return 0;
}
Atcoder Grand Contest 023 E - Inversions(线段树+扫描线)的更多相关文章
- AtCoder Grand Contest 023 E - Inversions
Description 给出长度为 \(n\) 序列 \(A_i\),求出所有长度为 \(n\) 的排列 \(P\),满足 \(P_i<=A_i\),求所有满足条件的 \(P\) 的逆序对数之和 ...
- AtCoder Grand Contest 001 C Shorten Diameter 树的直径知识
链接:http://agc001.contest.atcoder.jp/tasks/agc001_c 题解(官方): We use the following well-known fact abou ...
- AtCoder Grand Contest 023 A - Zero-Sum Ranges
Time limit : 2sec / Memory limit : 256MB Score : 200 points Problem Statement We have an integer seq ...
- Atcoder Grand Contest 023
A 略 B 略 C(计数) 题意: 有n个白球排成一行,故有n-1个空隙,我可以给一个空隙对应的两个白球都涂黑.n-1个空隙的一个排列就对应着一个涂黑顺序,定义这个涂黑顺序的价值是“将所有n个球都涂黑 ...
- AtCoder Grand Contest 023 C - Painting Machines
Description 一个长度为 \(n\) 的序列,初始都为 \(0\),你需要求出一个长度为 \(n-1\) 的排列 \(P\), 按照 \(1\) 到 \(n\) 的顺序,每次把 \(P_i\ ...
- AtCoder Grand Contest 023 F - 01 on Tree
Description 题面 Solution HNOI-day2-t2 复制上去,删点东西,即可 \(AC\) #include<bits/stdc++.h> using namespa ...
- AtCoder Grand Contest 011
AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...
- AtCoder Grand Contest 012
AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...
- AtCoder Grand Contest 010
AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...
随机推荐
- Java:volatile笔记
Java:volatile笔记 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. volatile 和 JMM 内存模型的可见性 JUC 下的三个包 java ...
- UltraSoft - Beta - Scrum Meeting 8
Date: May 24th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 记录Scrum Meeting Liuzh 前端 暂无 Kkkk 前端 暂无 王f ...
- (二)、Docker 快速入门
文档:https://docs.docker.com/install/linux/docker-ce/centos/ 中文文档:https://docs.docker-cn.com/engine/in ...
- The entitlements specified in your application’s Code Signing Entitlements file do not match those s
今天给打包 TPshop IOS (搜豹商城) ipa文件 调试运行 xcode运行提示这个错误: The entitlements specified in your application's C ...
- Luogu P2081 [NOI2012]迷失游乐园 | 期望 DP 基环树
题目链接 基环树套路题.(然而各种错误调了好久233) 当$m=n-1$时,原图是一棵树. 先以任意点为根做$dp$,求出从每一个点出发,然后只往自己子树里走时路径的期望长度. 接着再把整棵树再扫一遍 ...
- hdu 1198 Farm Irrigation(并查集)
题意: Benny has a spacious farm land to irrigate. The farm land is a rectangle, and is divided into a ...
- 20191310Lee_yellow缓冲区溢出实验
缓冲区溢出实验 1.什么是缓冲区溢出 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况.这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段.这一漏洞的出现是由于数据 ...
- Code Runner for VS Code,下载量突破 3000 万!
还记得五年前的夏天,我在巨硬写着世界上最好的语言,有时也需要带着游标卡尺写着另一门语言.然而,我对这两门语言都不熟悉,如果能在 VS Code 中方便快捷地运行各种语言,那岂不是很方便?于是,我就开发 ...
- k8s入坑之路(4)kubenetes安装
三种安装方法: 1.kubeadm 2.kubespray 3.二进制安装 kubespray安装kubernetes集群 优点: 1.kuberspray对比kubeadm更加简洁内部集成了kube ...
- coding game, 边打游戏边学编程,是一种怎么样的体验?
前言 hello,大家好,我是bigsai,好久不见,甚是想念! 在日常生活中,很多人喜欢玩游戏,因为游戏中有着对抗博弈.控制的喜悦,用灵魂指法完成一波靓丽的操作. 但实际上,你的按键都是对应代码中一 ...