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;
}

浙公网安备 33010602011771号