CF1096F Inversion Expectation

逆序对分三类:

1.已知对已知

树状数组直接处理即可

2.未知对未知

设未知数的位置数为\(m\),则有\(m(m-1)/2\)个数对。一个数对是逆序对的期望是\(0.5\)(一个逆序对与一个非逆序对对应)。因为期望的可加性,总期望为\(m(m-1)/4\)

3.已知对未知

处理出对于每个数\(i\),比它大且可填入原序列的数的个数\(a_i\)和比它小且可填入原序列的数的个数\(b_i\)

如果未知数在已知数\(i\)的左边,期望为\(a_i/m\),否则为\(b_i/m\),全加起来就行了

代码:

#include <bits/stdc++.h>
#define mod 998244353ll
#define ll long long
#define rep(i,x,y) for(i=x;i<=y;++i)
#define des(i,x,y) for(i=x;i>=y;--i)
#define rd(x) scanf("%d",&x)
#define N 200005
using namespace std;

int a[N],bg[N],sm[N],n;
ll c[N],t[N];
bool vis[N];

inline ll ksm(ll x,ll y){
    ll z=1;
    while(y){
        if(y&1) (z*=x)%=mod;
        (x*=x)%=mod,y>>=1;
    }
    return z;
}
inline int lowbit(int x){ return x&(-x);}
inline void add(ll *a,int x,int y){
    for(int i=x;i<=n;i+=lowbit(i)) (a[i]+=y)%=mod;
}
inline ll query(ll *a,int x){
    ll tmp=0;
    for(int i=x;i>0;i-=lowbit(i))
        (tmp+=a[i])%=mod;
    return tmp;
}

int main(){
    int i,tot=0;
    ll ans=0,inv;
    rd(n);
    rep(i,1,n){
        rd(a[i]);
        if(a[i]==-1) tot++; 
        else vis[a[i]]=1;
    }
    inv=ksm(1ll*tot,mod-2);
    (ans+=1ll*tot*(tot-1)%mod*ksm(4ll,mod-2)%mod)%=mod;
    bg[n]=0,sm[1]=0;
    des(i,n-1,1) bg[i]=bg[i+1]+(!vis[i+1]);
    rep(i,2,n) sm[i]=sm[i-1]+(!vis[i-1]);
    rep(i,1,n){
        if(~a[i]) add(c,a[i],sm[a[i]]*inv%mod);
        else (ans+=query(c,n))%=mod;
    }
    memset(c,0,sizeof(c));
    des(i,n,1){
        if(~a[i]){
            (ans+=query(t,a[i]))%=mod;
            add(t,a[i],1),add(c,a[i],bg[a[i]]*inv%mod);
        } else (ans+=query(c,n))%=mod;
    }
    printf("%I64d",ans);
}

猜你喜欢

转载自www.cnblogs.com/PsychicBoom/p/10418057.html