• 【codeforces 749E】 Inversions After Shuffle


    http://codeforces.com/problemset/problem/749/E (题目链接)

    题意

      给出一个1~n的排列,从中等概率的选取一个连续段,设其长度为l。对连续段重新进行等概率的全排列,求排列后整个原序列的逆序对的期望个数。

    Solution

      考虑对于每一对数${(a_i,a_j),i<j}$算贡献。


       1.连续段包含${a_i,a_j}$

      不妨设${a_i<a_j}$,则只有当排列后${a_j}$再${a_i}$前面才会对答案有贡献(${a_i>a_j}$的情况同理),连续段长度为${l}$。

      于是满足${a_i}$在${a_j}$前面的排列数为${P_l^{l-2}}$,概率:${frac{P_l^{l-2}}{P_l^l}=frac{1}{2}}$。

      满足包含${a_i}$和${a_j}$的连续段有${i*(n-j+1)}$个,其概率为:${frac{2*i*(n-j+1)}{n*(n+1)}}$。

      所以其期望等于两个概率相乘:

      $${q_{i,j}=frac{i*(n-j+1)}{n*(n+1)}}$$

      这是${O(n^2)}$的,考虑优化。总期望:

      $${Q=sum_{i=1}^n  sum_{j=i+1}^n  q_{i,j}}$$

      $${Q=sum_{i=1}^n  sum_{j=i+1}^n  frac{i*(n-j+1)}{n*(n+1)}}$$

      发现${(n-j+1)}$是连续的,于是就变成了:

      $${Q=sum_{i=1}^n  frac {i*(n-i)*(n-i+1)} {2*n*(n+1)}}$$

      这样复杂度就是${O(n)}$的了。


      2.连续段不同时包含${a_i,a_j}$

      如果${a_i<a_j}$,那么因为不被连续段同时包含,它们不会有机会改变相对位置,所以不会对答案做出贡献。考虑${a_i>a_j}$的情况。

      那么连续段可能取到的区间有:${[1,j-1],[i+1,n]}$。考虑到区间${[i+1,j-1]}$被算了2次,容斥一下,所以区间的概率:

      $${P_{i,j}=frac  {(j-1)*j+(n-i)*(n-i+1)-(j-i-1)*(j-i)}  {n*(n+1)}}$$

      $${P_{i,j}=frac  {(n^2+n)-(2*i+2*n*i)+2*i*j}  {n*(n+1)}}$$

      这个${P_{i,j}}$怎么快速求解呢,考虑逆序对这个东西。

      $${Q=sum_{i=1}^n  sum_{j=i+1}^n  frac  {(n^2+n)-(2*i+2*n*i)+2*i*j}  {n*(n+1)}}$$

      设满足${a_j<a_i,j>i}$的${a_j}$的个数为${x}$,显然${x}$我们可以通过树状数组用求逆序对的方法${O(nlogn)}$的求出来,则:

      $${Q=sum_{i=1}^n  frac  {x*((n^2+n)-(2*i+2*n*i))  +  sum_{j=i+1}^n 2*i*j}  {n*(n+1)}}$$

      那么现在${sum_{j=i+1}^n 2*i*j}$怎么求呢。把${2*i}$提出去,那么就成了${2*i*sum_{j=i+1}^n j}$我们用${y}$记录满足${a_j<a_i,j>i}$的${a_j}$的位置的和,也就是${sum_{j=i+1}^n j}$,那么显然这个东西我们也是可以通过树状数组用求逆序对的方法${O(nlogn)}$的算出来的。则:

      $${Q=sum_{i=1}^n  frac  {x*((n^2+n)-(2*i+2*n*i))  +  2*i*y}  {n*(n+1)}}$$

      于是问题就${O(nlogn)}$的解决了。

    细节

      mdzz不晓得哪里爆掉了还是精度问题,调了2天,最后莫名AC。。。

    代码

    // codeforces 749E
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf 1<<30
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100010;
    LL c[maxn],s[maxn],n;
    int a[maxn];
    long double ans;
    
    int lowbit(int x) {
    	return x&-x;
    }
    void add(LL *c,int x,LL val) {
    	for (int i=x;i<=n;i+=lowbit(i)) c[i]+=val;
    }
    LL query(LL *c,int x) {
    	LL res=0;
    	for (int i=x;i;i-=lowbit(i)) res+=c[i];
    	return res;
    }
    
    void solve1() {   //区间包含
    	long double Q=0;
    	for (LL i=1;i<=n;i++)
    		Q+=(long double)(i*(n-i)*(n-i+1))/2/n/(n+1);
    	ans+=Q;
    }
    void solve2() {   //区间不包含
    	long double Q=0;
    	for (int i=n;i>=1;i--) {
    		LL x=query(c,a[i]-1);
    		Q-=(long double)(x*((2*i+2*n*i)-(n*n+n)))/n/(n+1);
    		Q+=(long double)(2*i)/n/(n+1)*query(s,a[i]-1);
    		add(c,a[i],1);
    		add(s,a[i],i);
    	}
    	ans+=Q;
    }
    int main() {
    	scanf("%lld",&n);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	solve1();
    	solve2();
    	printf("%.20Lf",ans);
    	return 0;
    }
    

    贴一个暴力,供参考:

    // codeforces 749E
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf 1<<30
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
     
    const int maxn=100010;
    LL c[maxn],s[maxn],n;
    int a[maxn];
    long double ans;
     
    int main() {
    	freopen("aaa.in","r",stdin);freopen("ccc.out","w",stdout);
        scanf("%lld",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        for (LL i=1;i<=n;i++)
            ans+=(long double)(i*(n-i)*(n-i+1))/(2*n*(n+1));
    	long double res=0;
        for (LL i=n;i>=1;i--) {
    		for (LL j=i+1;j<=n;j++)
                if (a[i]>a[j]) res+=(long double)((j-1)*j+(n-i)*(n-i+1)-(j-i-1)*(j-i))/(n*(n+1));
    	}
    	ans+=res;
        printf("%.20Lf",ans);
        return 0;
    }
    
  • 相关阅读:
    一张图片入门Python
    4.1. 如何在Windows环境下开发Python
    你必须知道的EF知识和经验
    XUnit的使用
    如何使用NUnit
    Entity Framework 不支持DefaultValue
    Have You Ever Wondered About the Difference Between NOT NULL and DEFAULT?
    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details
    Entity Framework 与多线程
    sqlite中的自增主键
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6246624.html
Copyright © 2020-2023  润新知