AT3956 [AGC023E] Inversions

题解

考虑总方案数是:

\[f(n)=\prod_{i=1}^n (a_i-i+1)\\ s.t. \forall 1\le i<n,a_i\le a_{i+1} \]

我们令 \(a_i\) 的排名为 \(b_i\)\(c_i\) 为排好序后的 \(a_i\),即:

\[c_{b_i}=a_i\\ f(n)=\prod_{i=1}^n (a_i-b_i+1)=\prod_{i=1}^n(c_i-i+1) \]

考虑每两个位置的对于逆序对的贡献,不妨先设这两个位置为 \(i\)\(j\)

\(j<i\)\(a_j<a_i\) ,我们求其的逆序对贡献。

由于是逆序对,所以 \(a_i\)\(a_j\) 大的部分可以省去,然后发现就是这样?

\[f(i,j)=\frac{f(n)\times\frac{a_j-b_j}{a_i-b_i+1}\times(\prod_{k=b_j+1}^{b_i-1}\frac{c_k-k}{c_k-k+1})}{2} \]

这个式子的组合意义实际上就是求出在 \(a_i\)\(a_j\) 相同的时候的总方案数,然后除以 \(2\) ,就是 \(p_j>p_i\) 的方案数了。

\(i<j\)\(a_i>a_j\) ,我们可以求其的顺序对贡献,用总的减去它。

\[f(i,j)=f(n)-\frac{f(n)\times\frac{a_j-b_j}{a_i-b_i+1}\times(\prod_{k=b_j+1}^{b_i-1}\frac{c_k-k}{c_k-k+1})}{2} \]

发现对于前后的,只有一小部分不一样,我们考虑先来处理共同部分:

\[g(i,j)=\frac{f(n)\times\frac{a_j-b_j}{a_i-b_i+1}\times(\prod_{k=b_j+1}^{b_i-1}\frac{c_k-k}{c_k-k+1})}{2}\\ =\frac{f(n)}{2(a_i-b_i+1)}\times(a_j-b_j)\times\prod_{k=b_j+1}^{b_i-1}\frac{c_k-k}{c_k-k+1} \]

前面的这个东西对于每一个 \(i\) 都是一样的,后面的一半可以用线段树来维护,我们考虑从小到大往线段树中添加东西,对于当前位置 \(i\) ,令其排名为 \(k\) ,排名比其小的部分已经在线段树中了,我们考虑直接提取出区间和,然后对于全局进行一个区间乘 \(\frac{c_k-k}{c_k-k+1}\) ,同时将位置 \(i\) 的部分改为 \(a_i-b_i\) 就可以了吧。

代码如下

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
const int MOD=1e9+7;
int n;
struct Data{int data,pos;}a[N];
bool cmp(const Data a,const Data b){return a.data<b.data;}
int ksm(int x,int k){
	int res=1;
	for(;k;k>>=1,x=x*x%MOD)
	if(k&1) res=res*x%MOD;
	return res;
}
struct Seg_Tree{
	struct Node{int data,tag;}tr[N<<2];
	void up(int u){tr[u].data=(tr[u<<1].data+tr[u<<1|1].data)%MOD;}
	void updata(int u,int z){
		tr[u].data*=z,tr[u].data%=MOD;
		tr[u].tag*=z,tr[u].tag%=MOD;
	}
	void down(int u){
		updata(u<<1,tr[u].tag);
		updata(u<<1|1,tr[u].tag);
		tr[u].tag=1;
	}
	void build(int u,int l,int r){
		tr[u].tag=1;
		if(l==r) return ;
		int mid=(l+r)>>1;
		build(u<<1,l,mid);
		build(u<<1|1,mid+1,r);
		return ;
	}
	int query(int u,int l,int r,int x,int y){
		if(x>y) return 0;
		if(x<=l&&r<=y) return tr[u].data;
		int mid=(l+r)>>1,res=0;down(u);
		if(x<=mid) res+=query(u<<1,l,mid,x,y);
		if(y>mid) res+=query(u<<1|1,mid+1,r,x,y);
		return res%MOD;
	}
	void chg(int u,int l,int r,int x,int z){
		if(l==r) return (void)(tr[u].data=z);
		int mid=(l+r)>>1;down(u);
		if(x<=mid) chg(u<<1,l,mid,x,z);
		else chg(u<<1|1,mid+1,r,x,z);
		return up(u);
	}
}t1;
struct Tree_Array{
	int tr[N];
	int lowbit(int x){return x&(-x);}
	void add(int k,int x){for(;k<=n;k+=lowbit(k))tr[k]+=x;}
	int query(int k){int res=0;for(;k;k-=lowbit(k))res+=tr[k];return res;}
}t2;
int res=0,tot=1;
signed main(){
	cin>>n;
	for(int i=1;i<=n;++i) scanf("%lld",&a[i].data),a[i].pos=i;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;++i) tot*=a[i].data-i+1,tot%=MOD;
	for(int i=1;i<=n;++i){
		int tmp=0;
		tmp+=t1.query(1,1,n,1,a[i].pos-1),tmp%=MOD;
		tmp+=MOD-t1.query(1,1,n,a[i].pos+1,n),tmp%=MOD;
		tmp*=tot*ksm(2*(a[i].data-i+1),MOD-2)%MOD,tmp%=MOD;
		tmp+=(t2.query(n)-t2.query(a[i].pos))*tot%MOD,tmp%=MOD;
		// printf("%lld %lld %lld\n",a[i].data,a[i].pos,tmp);
		res+=tmp,res%=MOD;
		t1.updata(1,(a[i].data-i)*ksm(a[i].data-i+1,MOD-2)%MOD);
		t1.chg(1,1,n,a[i].pos,a[i].data-i),t2.add(a[i].pos,1);
	}
	printf("%lld\n",res);
	return 0;
}
posted @ 2021-01-04 14:41  Point_King  阅读(98)  评论(0)    收藏  举报