zoukankan      html  css  js  c++  java
  • #4229. Inverse

    题目描述

    小C有一个 $1$ 到 $n$ 的排列 $P$,他会进行 $k$ 次操作,每次等概率选择一段连续区间(每次有 $frac{n(n+1)}{2}$ 种选择),然后翻转这个区间。

    小C想知道 $k$ 次操作后逆序对的期望个数,他觉得这实在是个一眼题,于是这个任务就交给你了。

    为了避免精度误差,你只需要输出期望在模 $10^9 + 7$ 意义下的结果。

    题解

    考虑 $(i,j)$ 的贡献,于是设计dp: $f[i][j][k]$ 表示 $(i,j)$ 在 $k$ 轮之后 $p_i>p_j$ 的概率, $g[i][j][k]$ 表示 $p_i<p_j$的概率,其中 $i<j$ 。

    考虑 $f$ 的转移,假设第 $k$ 轮翻转 $[l,r]$ ,设 $U=frac{2}{n(n-1)}$ ,分类一下:
    1. $l in [1,i],r in [i,j)$ ,贡献为 $U imes f[l+r-i][j][k-1]$ ;
    2. $l in (i,j],r in [j,n]$ ,贡献为 $U imes f[i][l+r-j][k-1]$ ;
    3. $l in (i,j),r in (i,j) || l in (j,n] || r in [1,i)$ ,贡献为 $U imes f[i][j][k-1]$ ;
    4. $l in [1,i],r in [j,n]$ ,贡献为 $U imes g[l+r-j][l+r-i][k-1]$ 。

    $g$ 的转移是类似的。

    对于前两个来说,我们发现有一维是固定的,所以另一维做二次前缀和即可,对于第四个来说,我们发现它的差是固定的,所以对于差我们做二次前缀和即可,因此效率为 $O(n^2k)$

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=505,P=1e9+7;
    int f[2][N][N],g[2][N][N][3],h[2][N][N][3],s[2][N][N][3],a[N],n,m,V,ans,F[2][N][N];
    inline int X(int x){return x>=P?x-P:x;}
    int K(int x,int y){
        int z=1;
        for (;y;y>>=1,x=1ll*x*x%P)
            if (y&1) z=1ll*z*x%P;
        return z;
    }
    inline int H(int i,int j,int o){
        int u,v,x,y;
        v=1ll*h[o][j-1][j][2]*i%P;
        x=X(h[o][i][j][1]-1ll*h[o][i][j][2]*(n-i)%P+P);
        y=X(X(h[o][j-1][j][0]-h[o][j-i-1][j][0]+P)-1ll*(h[o][j-1][j][2]-h[o][j-i-1][j][2]+P)*(j-i)%P+P);
        u=X(v+P-X(x+y));
        
        v=1ll*g[o][i][n][2]*(j-i)%P;
        x=X(g[o][i][j][1]-1ll*g[o][i][j][2]*(n-j)%P+P);
        y=X(X(g[o][i][n][0]-g[o][i][n+i-j][0]+P)-1ll*(g[o][i][n][2]-g[o][i][n+i-j][2]+P)*(n+i-j+1)%P+P);
        u=X(u+X(v+P-X(x+y)));
        
        o^=1;
        v=1ll*s[o][n+i-j][j-i][2]*i%P;
        x=X(1ll*s[o][i][j-i][1]-1ll*s[o][i][j-i][2]*(n-i)%P+P);
        y=X(X(s[o][n+i-j][j-i][0]-s[o][n-j][j-i][0]+P)-1ll*(s[o][n+i-j][j-i][2]-s[o][n-j][j-i][2]+P)*(n-j+1)%P+P);
        return X(u+X(v+P-X(x+y)));
    }
    int main(){
        cin>>n>>m;V=X(K(n*(n+1),P-2)<<1);
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for (int i=1;i<=n;i++)
            for (int j=i+1;j<=n;j++)
                f[a[i]<a[j]][i][j]=1;
        for (int k=1;k<=m;k++){
            for (int o=0;o<2;o++)
                for (int i=1;i<=n;i++){
                    for (int j=i+1;j<=n;j++)
                        g[o][i][j][0]=X(g[o][i][j-1][0]+1ll*j*f[o][i][j]%P),
                        g[o][i][j][1]=X(g[o][i][j-1][1]+1ll*(n-j)*f[o][i][j]%P),
                        g[o][i][j][2]=X(g[o][i][j-1][2]+f[o][i][j]),
                        s[o][i][j-i][0]=X(s[o][i-1][j-i][0]+1ll*i*f[o][i][j]%P),
                        s[o][i][j-i][1]=X(s[o][i-1][j-i][1]+1ll*(n-i)*f[o][i][j]%P),
                        s[o][i][j-i][2]=X(s[o][i-1][j-i][2]+f[o][i][j]);
                    for (int j=1;j<i;j++)
                        h[o][j][i][0]=X(h[o][j-1][i][0]+1ll*j*f[o][j][i]%P),
                        h[o][j][i][1]=X(h[o][j-1][i][1]+1ll*(n-j)*f[o][j][i]%P),
                        h[o][j][i][2]=X(h[o][j-1][i][2]+f[o][j][i]);
                }
            for (int o=0;o<2;o++){
                for (int i=1;i<=n;i++)
                    for (int j=i+1;j<=n;j++)
                        f[o][i][j]=1ll*(h[o][i][j][2]-h[o][i-1][j][2]+P)*(((j-i-1)*(j-i)+(i-1)*i+(n-j)*(n-j+1))>>1)%P,
                        f[o][i][j]=1ll*V*X(f[o][i][j]+H(i,j,o))%P;
            }
        }
        for (int i=1;i<=n;i++)
            for (int j=i+1;j<=n;j++)
                ans=X(ans+f[0][i][j]);
        cout<<ans<<endl;return 0;
    }

     

  • 相关阅读:
    代码习惯
    全网最详细的fhq treap (非旋treap)讲解
    按位或「HAOI2015」
    列队「NOIP2017」
    愤怒的小鸟「NOIP2016」
    能量传输「CSP多校联考 2019」
    矿物运输「CSP多校联考 2019」
    普通打击「CSP多校联考 2019」
    普通快乐「CSP多校联考 2019」
    BZOJ4385: [POI2015]Wilcze doły
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12301711.html
Copyright © 2011-2022 走看看