CF749E Inversions After Shuffle

Link
我们可以把贡献拆成两部分计算。
对于一对(a_i,a_j(i<j)),如果我们重排的区间([l,r])满足([i,j]subseteq[l,r]),那么不论(a_i,a_j)的关系如何,它们都有(frac12)的概率产生(1)的贡献。
这里的总的贡献是(frac{sumlimits_{i=1}^nsumlimits_{j=i+1}^ni(n-j+1)}{n(n+1)}=frac{sumlimits_{i=1}^ni(n-i)(n-i+1)}{n(n+1)})
其实可以推出(O(1))的式子,不过没有必要了。
对于一对(a_i,a_j(i<jwedge a_i>a_j)),如果我们重排的区间([l,r])满足([i,j] otsubseteq[l,r]),那么它们就会产生(1)的贡献。
这里总的贡献是(frac{sumlimits_{i=1}^nsumlimits_{j=i+1}^n[a_i>a_j][n(n+1)-i(n-j+1)]}{n(n+1)}=sumlimits_{i=1}^nsumlimits_{j=i+1}^n[a_i>a_j]-frac{sumlimits_{i=1}^nsumlimits_{j=i+1}^n[a_i>a_j]i(n-j+1)}{n(n+1)})
树状数组维护一下就好了。

#include<cstdio>
#include<cctype>
const int N=100007;
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
using db=double;
using ll=long long;
int n;
struct bit
{
    ll t[N];
    void add(int p,int v){for(;p;p^=p&-p)t[p]+=v;}
    ll ask(int p){ll s=0;for(;p<=n;p+=p&-p)s+=t[p];return s;}
}t1,t2;
int main()
{
    n=read();db ans=0,Ans=0;
    for(int i=1,a;i<=n;++i) a=read(),Ans+=t1.ask(a+1),ans+=(db)(n-i+1)*i*(n-i)/4.0-(db)t2.ask(a+1)*(n-i+1),t1.add(a,1),t2.add(a,i);
    printf("%.10lf",Ans+ans/(1ll*n*(n+1)>>1));
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12193934.html