1. 程式人生 > >CF1096F Inversion Expectation [期望]

CF1096F Inversion Expectation [期望]

題意

  給你一個長為$n$的排列,若某一位為$−1$則這一位是不確定的。每種可能的排列出現的概率相等。求期望逆序對數對$998244353$取模的結果。


分類討論一下:

  1. 已知位置之間貢獻:樹狀陣列計算

  2.未知位置之間貢獻:$\frac{\tbinom{m}{2}}{2}=\frac{1}{4}m(m-1)$ ($m$為未知位置個數)

  3.已知和未知之間貢獻:

    對於每個未知的位置,取不同值時前面比它大和後面比它小的數的個數。

    轉化一下就是:每個已知的位置貢獻為$$(前面未知位置個數\times比這個數大的未使用的數的個數+後面未知位置個數\times比這個數小的未使用的數的個數)\times m^{-1}$$

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N=200010;
 7 const ll P=998244353;
 8 ll n,a[N],app[N],b[N],m,c[N],inv,S;
 9 ll ans;
10 inline void add(int x) {for (; x<=n; x+=(x&-x)) c[x]++;}
11
inline ll sum(int x) {ll s=0; for (; x; x-=(x&-x)) s+=c[x]; return s;} 12 inline ll pow(ll x,ll k) {ll r=1; for (; k; k>>=1,x=x*x%P) if (k&1) r=r*x%P; return r;} 13 int main() { 14 scanf("%lld",&n); 15 for (int i=1; i<=n; i++) {scanf("%lld",&a[i]),m+=(a[i]==-1); if (~a[i]) app[a[i]]=1
;} 16 for (int i=1; i<=n; i++) { 17 b[i]=b[i-1]+(app[i]^1); 18 if (~a[i]) { 19 ans+=sum(n)-sum(a[i]); 20 add(a[i]); 21 } 22 } 23 ans=(ans%P)+1ll*m*(m-1)%P*748683265ll%P; //4^-1 24 inv=pow(m,P-2); S=0; 25 for (int i=1; i<=n; i++) { 26 if (~a[i]) S+=b[a[i]]; 27 else ans=(ans+1ll*S*inv%P)%P; 28 } 29 S=0; 30 for (int i=n; i; i--) { 31 if (~a[i]) S+=m-b[a[i]]; 32 else ans=(ans+1ll*S*inv%P)%P; 33 } 34 printf("%lld\n",ans); 35 return 0; 36 }