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\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...
随机推荐
- 初学Python-day1 运算符和数据类型
- 改善深层神经网络-week1编程题(Regularization)
Regularization Deep Learning models have so much flexibility and capacity that overfitting can be a ...
- 实用小技巧:Notepad++直接连接Linux
实用小技巧:Notepad++直接连接Linux 前言 号称编辑器之神的Vim对于只会用几个基础操作的本人而言,在编辑一些大型文本有那么些力不从心: 平时都是通过Xftp拖到本地,修改完后再覆盖回去: ...
- uni-app 安卓离线打包详细教程
借鉴 uni-app官方给出的文章http://ask.dcloud.net.cn/article/508(虽说是04年的) 预备环境 AndroidStudio开发环境,要求安装Android4.0 ...
- js fetch异步请求使用详解
目录 认识异步 fetch(url) response.json() 结合async和await 异常处理 post请求 认识异步 首先我们得明白请求是一个异步的过程. 因为请求需要时间向服务器发送请 ...
- 穿点最多的直线 牛客网 程序员面试金典 C++
穿点最多的直线 牛客网 程序员面试金典 C++ 题目描述 在二维平面上,有一些点,请找出经过点数最多的那条线. 给定一个点集vectorp和点集的大小n,没有两个点的横坐标相等的情况,请返回一个vec ...
- Luogu P1118 [USACO06FEB]数字三角形 Backward Digit Sums | 搜索、数学
题目链接 思路:设一开始的n个数为a1.a2.a3...an,一步一步合并就可以用a1..an表示出最后剩下来的数,不难发现其中a1..an的系数恰好就是第n层杨辉三角中的数.所以我们可以先处理出第n ...
- JAVA笔记2__类/封闭性/构造方法/方法的重载/匿名对象
public class Main { public static void main(String[] args) { Chicken c1 = new Chicken(); Chicken c2 ...
- 编译安装与gcc编译器
先说一下gcc编译器,只知道这是一个老款的编译器.编译的目的也比较重要,就是将c语言的代码编译成可以执行的binary文件. gcc 简单使用(后期补充) eg: gcc example.c # ...
- 解决mac主机无法与 Docker容器互通问题
方法很多,这里我说一下使用 docker-connector解决这个问题 这是一个github开源项目docker-connector 1. Mac 通过 brew 安装 docker-connec ...