P4223 期望逆序对 题解

大分讨题。

期望 \(\times {n\choose 2}^k\),即求每种情况的逆序对数之和。

考虑枚举所有 \(i<j\) 计算最终 \(a_i>a_j\) 的方案数。记 \(A=a_i,B=a_j\)\(C\) 表示除了 \(a_i,a_j\) 以外的任意一个数,发现最终 \((a_i,a_j)\) 只有 \(7\) 种情况:

\((A,B),(A,C),(B,C),(C,A),(C,B),(B,A),(C,C)\)

容易得到一个 \(7\times 7\) 的转移矩阵,快速幂求出 \((A,B)\) 转移到每种情况的方案数。接下来枚举 \(i<j\land a_i<a_j\) 考虑每种情况的贡献(\(a_i>a_j\) 类似):

  • \((A,B)\):无贡献。
  • \((A,C)\)\(C\) 可取 \([1,a_i-1]\) 中的任意一数,贡献为 \(\frac{a_i-1}{n-2}\)
  • \((B,C)\)\(C\) 可取 \([1,b_j-1]\) 中除了 \(a_i\) 的任意一数,贡献为 \(\frac{b_j-2}{n-2}\)
  • \((C,A)\):同理 \(\frac{n-a_i-1}{n-2}\)
  • \((C,B)\):同理 \(\frac{n-b_j}{n-2}\)
  • \((B,A)\):一定为逆序对,贡献为 \(1\)
  • \((C,C)\)\(>\)\(<\) 的对数相等,贡献为 \(\frac 1 2\)

考虑将 \(i\)\(j\) 的贡献分开算,发现对于一个指定的 \(i\),只需要知道前后 \(>a_i\)\(<a_i\) 的个数就能求出贡献,树状数组维护即可。

时间复杂度 \(\mathcal O(n\log n+\log k)\)

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define mxn 500003
#define md 1000000007
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
inline int read(){
	int x=0;char c=getchar();
	while(!isdigit(c))c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x;
}
struct node{
	ll a[8][8];
	inline void init(){
		memset(a,0,sizeof(a));
		rep(i,1,7)a[i][i]=1;
	}
	inline node operator*(node x){
		node s;
		rep(i,1,7)rep(j,1,7)s.a[i][j]=0;
		rep(i,1,7)rep(k,1,7)if(a[i][k])
			rep(j,1,7)s.a[i][j]=(s.a[i][j]+a[i][k]*x.a[k][j])%md;
		return s;
	}
}s,d,bs;
int n,k,q,a[mxn],c[mxn];
ll ans,n2,ni,cc,f[8];
inline ll pw(ll x,ll y){
	ll s=1;
	for(;y;y>>=1){
		if(y&1)s=s*x%md;
		x=x*x%md;
	}
	return s;
}
inline void power(int k){
	s.init(),bs=d;
	for(;k;k>>=1){
		if(k&1)s=s*bs;
		bs=bs*bs;
	}
}
inline void add(int x,int y){
	for(;x<=n;x+=x&-x)c[x]+=y;
}
inline int ask(int x){
	int s=0;
	for(;x;x-=x&-x)s+=c[x];
	return s;
}
void solve(){
	power(k);
	rep(i,1,n)c[i]=0;
	memset(f,0,sizeof(f));
	f[7]=n*(n-1ll)/2%md*((md+1ll)/2)%md;
	rep(i,1,n){
		ll c1=ask(a[i]),c2=i-1-c1;
		f[2]=(f[2]+(a[i]-1)*(n-a[i]-c2)+(a[i]-2)*(a[i]-1-c1))%md;
		f[3]=(f[3]+(a[i]-2)*c1+(a[i]-1)*c2)%md;
		f[4]=(f[4]+(n-a[i]-1)*(n-a[i]-c2)+(n-a[i])*(a[i]-1-c1))%md;
		f[5]=(f[5]+(n-a[i])*c1+(n-a[i]-1)*c2)%md;
		f[6]=(f[6]+c1)%md;
		add(a[i],1);
	}
	ans=0;
	ans=(ans+(cc-f[6])*s.a[1][1])%md;
	ans=(ans+f[2]*n2%md*s.a[1][2])%md;
	ans=(ans+f[3]*n2%md*s.a[1][3])%md;
	ans=(ans+f[4]*n2%md*s.a[1][4])%md;
	ans=(ans+f[5]*n2%md*s.a[1][5])%md;
	ans=(ans+f[6]*s.a[1][6])%md;
	ans=(ans+f[7]*s.a[1][7])%md;
	cout<<(ans%md+md)%md<<'\n';
}
signed main(){
	n=read(),k=read();
	n2=pw(n-2,md-2),cc=n*(n-1ll)/2%md,ni=pw(cc,md-2);
    rep(i,1,n)a[i]=read();
    d.a[1][1]=(n-2ll)*(n-3)/2%md,d.a[1][2]=n-2,d.a[1][5]=n-2,d.a[1][6]=1;
	d.a[2][1]=1,d.a[2][2]=((n-2ll)*(n-3)/2+n-3)%md,d.a[2][3]=1,d.a[2][4]=1,d.a[2][7]=n-3;
	d.a[3][2]=1,d.a[3][3]=((n-2ll)*(n-3)/2+n-3)%md,d.a[3][5]=1,d.a[3][6]=1,d.a[3][7]=n-3;
	d.a[4][2]=1,d.a[4][4]=((n-2ll)*(n-3)/2+n-3)%md,d.a[4][5]=1,d.a[4][6]=1,d.a[4][7]=n-3;
	d.a[5][1]=1,d.a[5][5]=((n-2ll)*(n-3)/2+n-3)%md,d.a[5][3]=1,d.a[5][4]=1,d.a[5][7]=n-3;
	d.a[6][1]=1,d.a[6][3]=n-2,d.a[6][4]=n-2,d.a[6][6]=(n-2ll)*(n-3)/2%md;
	d.a[7][2]=d.a[7][3]=d.a[7][4]=d.a[7][5]=1,d.a[7][7]=n*(n-1ll)/2%md-4;
    solve();
	return 0;
}
posted @ 2025-07-11 21:08  zifanwang  阅读(10)  评论(0)    收藏  举报