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\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...
随机推荐
- 自动化运维利器Ansible要点汇总
由于大部分互联网公司服务器环境复杂,线上线下环境.测试正式环境.分区环境.客户项目环境等造成每个应用都要重新部署,而且服务器数量少则几十台,多则千台,若手工一台台部署效率低下,且容易出错,不利后期运维 ...
- Bootstrap移动端导航(简易)
效果 在线查看 代码少,都在HTML里 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- 三分钟极速体验:Java版人脸检测
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Java:并发笔记-08
Java:并发笔记-08 说明:这是看了 bilibili 上 黑马程序员 的课程 java并发编程 后做的笔记 7. 共享模型之工具-1 7.1 线程池 1. 自定义线程池 步骤1:自定义拒绝策略接 ...
- 6月8日 Scrum Meeting
日期:2021年6月8日 会议主要内容概述: 确定6.9日下午两点到五点集中对接 初步确定主题配色和echarts默认图表颜色 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作 ...
- UltraSoft - Alpha - Scrum Meeting 8
Date: Apr 23th, 2020. Scrum 情况汇报 进度情况 组员 负责 昨日进度 后两日任务 CookieLau PM.后端 aliyun连接前后端,跑通demo 实现邮箱注册的验证码 ...
- OO第四单元UML作业总结暨OO课程总结
目录 目录一.第四单元UML两次作业架构设计第一次作业第二次作业二.架构设计总结与OO方法理解演进三.测试理解与实践演进四.课程收获总结五.课程改进建议六.尾声 一.第四单元UML两次作业架构设计 第 ...
- OO第四单元及学期总结
OO第四单元及学期总结 第四单元两次作业的架构设计 第一次作业 类图: 树形结构:使用Operation类管理UMLOperation以及parent为该UMLOperation的参数(UMLpara ...
- 洛谷 P4555 [国家集训队]最长双回文串
链接: P4555 题意: 在字符串 \(S\) 中找出两个相邻非空回文串,并使它们长度之和最大. 分析: 直接使用马拉车算法求出每个点扩展的回文串.如果枚举两个回文串显然会超时,我们考虑切割一个长串 ...
- VCS常用仿真选项开关及步骤总结
转自:https://blog.csdn.net/bcs_01/article/details/79803304 转自:https://blog.csdn.net/wonder_coole/artic ...