题解:CF749E Inversions After Shuffle

· · 题解

CF749E Inversions After Shuffle

题目大意

给定一个排列,随机打乱其中一部分,求期望的逆序对个数。

解题思路

考虑对于一个数对 (a_i,a_j),i<j

如果 (a_i,a_j) 被包含在打乱的区间中,则会产生一半的正贡献或一半的负贡献。

(a_i,a_j)$ 被包含在打乱的区间中的概率为:$\frac{i\times (n-j+1)}{\frac{1}{2}\times n\times (n+1)} = \frac{2\times i \times (n-j+1)}{n\times (n+1)}

那么:

同理,$a_i<a_j$,则**减少的逆序对个数**减少 $\frac{1}{2}\times \frac{2\times i\times (n-j+1)}{n\times (n+1)} = \frac{i\times (n-j+1)}{n\times (n+1)}$。 可以用树状数组维护,建两颗树状数组,一颗计算原序列逆序对个数,另一颗维护上述的**减少逆序对的个数**,二者相减即可。 这里给出核心代码(树状数组略): ```cpp void solve(){ int n; cin>>n; vector<int> a(n+1); for(int i=1;i<=n;i++){ cin>>a[i]; } Tr1.init(n),Tr2.init(n); double cnt=0,ans=0; for(int i=1;i<=n;i++){ cnt+=Tr1(n)-Tr1(a[i]); Tr1.add(a[i],1); } for(int i=1;i<=n;i++){ ans+=(n-i+1)*(Tr2(n)-Tr2(a[i])); ans-=(n-i+1)*Tr2(a[i]); Tr2.add(a[i],i); } ans/=n*(n+1); cout<<fixed<<setprecision(12)<<cnt-ans<<endl; } ```