题解
考虑总方案数是:
[f(n)=prod_{i=1}^n (a_i-i+1)\
s.t. forall 1le i<n,a_ile 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) imesfrac{a_j-b_j}{a_i-b_i+1} imes(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) imesfrac{a_j-b_j}{a_i-b_i+1} imes(prod_{k=b_j+1}^{b_i-1}frac{c_k-k}{c_k-k+1})}{2}
]
发现对于前后的,只有一小部分不一样,我们考虑先来处理共同部分:
[g(i,j)=frac{f(n) imesfrac{a_j-b_j}{a_i-b_i+1} imes(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)} imes(a_j-b_j) imesprod_{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
",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
",res);
return 0;
}