洛谷题面传送门 & Atcoder 题面传送门

毒瘤 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\) 数组排序后的结果,那么

\[C=\prod\limits_{i=1}^n(b_i-i+1)
\]

我们考虑从这个性质入手计算符合要求的排列个数。对于一对 \((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\)​ 中的数的排名提升一格,即

\[C'=C·\dfrac{a_i-r_i}{a_j-r_j+1}·\prod\limits_{k=r_i+1}^{r_j-1}\dfrac{b_k-k}{b_k-k+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(线段树+扫描线)的更多相关文章

  1. AtCoder Grand Contest 023 E - Inversions

    Description 给出长度为 \(n\) 序列 \(A_i\),求出所有长度为 \(n\) 的排列 \(P\),满足 \(P_i<=A_i\),求所有满足条件的 \(P\) 的逆序对数之和 ...

  2. AtCoder Grand Contest 001 C Shorten Diameter 树的直径知识

    链接:http://agc001.contest.atcoder.jp/tasks/agc001_c 题解(官方): We use the following well-known fact abou ...

  3. AtCoder Grand Contest 023 A - Zero-Sum Ranges

    Time limit : 2sec / Memory limit : 256MB Score : 200 points Problem Statement We have an integer seq ...

  4. Atcoder Grand Contest 023

    A 略 B 略 C(计数) 题意: 有n个白球排成一行,故有n-1个空隙,我可以给一个空隙对应的两个白球都涂黑.n-1个空隙的一个排列就对应着一个涂黑顺序,定义这个涂黑顺序的价值是“将所有n个球都涂黑 ...

  5. AtCoder Grand Contest 023 C - Painting Machines

    Description 一个长度为 \(n\) 的序列,初始都为 \(0\),你需要求出一个长度为 \(n-1\) 的排列 \(P\), 按照 \(1\) 到 \(n\) 的顺序,每次把 \(P_i\ ...

  6. AtCoder Grand Contest 023 F - 01 on Tree

    Description 题面 Solution HNOI-day2-t2 复制上去,删点东西,即可 \(AC\) #include<bits/stdc++.h> using namespa ...

  7. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

  8. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  9. AtCoder Grand Contest 010

    AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...

随机推荐

  1. javascriptRemke之类的继承

    前言:es6之前在js中要实现继承,就必须要我们程序员在原型链上手动继承多对象的操作,但是结果往往存在漏洞,为解决这些问题,社区中出现了盗用构造函数.组合继承.原型式继承.寄生式继承等一系列继承方式, ...

  2. Convolutional Neural Network-week2编程题1(Keras tutorial - 笑脸识别)

    本次我们将: 学习到一个高级的神经网络的框架,能够运行在包括TensorFlow和CNTK的几个较低级别的框架之上的框架. 看看如何在几个小时内建立一个深入的学习算法. 为什么我们要使用Keras框架 ...

  3. 谈谈BEM规范(含代码)

    css规范之BEM规范 前言 引用一句经典名言在编程的世界里其中一件最难的事情就是命名,不管是设计到编程语言还是标记语言都会有命名的需求.今天聊的就是关于css的命名规范的发展过程以及演变. 命名的发 ...

  4. 无网络下,配置yum本地源

    1. 新建一个没有iso镜像文件的虚拟机: 2. 本地上传一个镜像文件(CentOS7的镜像),到虚拟机已创建的目录: 例如:上传一个镜像文件CentOS-7-x86_64-Everything-17 ...

  5. 2021.9.9考试总结[NOIP模拟50]

    T1 第零题 神秘结论:从一个点满体力到另一个点的复活次数与倒过来相同. 于是预处理出每个点向上走第$2^i$个死亡点的位置,具体实现可以倍增或二分. 每次询问先从两个点同时向上倍增,都转到离$LCA ...

  6. pyqgis环境配置

    配置pyqgis开发环境时,很多网上教程写的非常繁琐,这里仅仅找了一个最简单的配置方法,使用pycharm的IDE,安装QGIS软件后,在pycharm的ProjectInterpreter里面填写Q ...

  7. C语言单片机项目实战超声波雷达测距

    本实验是基于MSP430利用HC-SR04超声波传感器进行测距,测距范围是3-65cm,讲得到的数据显示在LCD 1602液晶屏上. 模块工作原理如下 (1)采用 IO 触发测距,给至少 10us 的 ...

  8. 轻松掌握stm32直流电机驱动与测速

    说实话就现在的市场应用中stm32已经占到了绝对住到的地位,51已经成为过去式,32的功能更加强大,虽然相应的难度有所增加,但是依然阻止不了大家学习32的脚步,不说大话了这些大家都懂要不然也不会学习s ...

  9. 你一定不知道的Unsafe用法

    Unsafe是什么 首先我们说Unsafe类位于rt.jar里面sun.misc包下面,Unsafe翻译过来是不安全的,这倒不是说这个类是不安全的,而是说开发人员使用Unsafe是不安全的,也就是不推 ...

  10. (转)linux下错误的捕获:errno和strerror的使用,以及perror和strerror的区别

    经常在调用linux 系统api 的时候会出现一些错误,比方说使用open() write() creat()之类的函数有些时候会返回-1,也就是调用失败,这个时候往往需要知道失败的原因.这个时候使用 ...