dtoj#4229. Inverse
题目描述:
小C有一个 $1$ 到 $n$ 的排列 $P$,他会进行 $k$ 次操作,每次等概率选择一段连续区间(每次有 $\frac{n(n+1)}{2}$ 种选择),然后翻转这个区间。
小C想知道 $k$ 次操作后逆序对的期望个数,他觉得这实在是个一眼题,于是这个任务就交给你了。
为了避免精度误差,你只需要输出期望在模 $10^9 + 7$ 意义下的结果。
算法标签:前缀和套前缀和DP优化
思路:
$f[i][j][k]$ 表示 $i,j$ 这两个位置经过 $k$ 次操作,$ai>aj$ 的概率。
第一类:
(区间不覆盖 $i, j$ )
$$
f[i][j][k]+=\sum_{r=1}^{r\le i-1}\sum_{l=1}^{l\le r}f[l][r][k-1]\times P
$$
$$
f[i][j][k]+=\sum_{l=j+1}^{l\le n}\sum_{r=l}^{r\le n}f[l][r][k-1]\times P
$$
总结起来就是:
$$
f[i][j][k]+=f[i][j][k-1]\times P\times (\frac{i\times (i-1)}{2}+\frac{(n-j)\times (n-j+1)}{2}+\frac{(j-i)\times (j-i-1)}{2})
$$
第二类:
(区间只覆盖 $i,j$ 中的一个)
$$
f[i][j][k]+=\sum_{l=1}^{l\le i}\sum_{r=i}^{r\le j-1}f[l+r-i][j][k-1]\times P
$$
当发现 $j$ 是固定的所以对其前缀和
$$
f[i][j][k]+=\sum_{l=1}^{l\le i}(s1[l-i+j-1][j]-s1[l-1][j])\times P
$$
发现第二位仍然是一样的,再进行一次前缀和
$$
f[i][j][k]+=(s2[j-1][j]-s2[j-i-1][j]-s2[i-1][j])\times P
$$
$$
f[j][j][k]+=\sum_{l=i+1}^{l\le r}\sum_{r=j}^{r<=n}f[i][l+r-j][k-1]\times P()
$$
这个式子同上用两次前缀和化简。
第三类:
(区间同时覆盖了 $i, j$ ,意味着两者逆序对的方案数发生变化)
$$
f[i][j][k]+=\sum_{l=1}^{l\le i}\sum_{r=j}^{r\le n}(1-f[l+r-i][l+r-j][k-1])\times P
$$
这类的化简有点不同,发现每一项都在变化,但是发现第一项和第二项的距离不变。
所以考虑令 $g1[i][j]$ 表示f的距离为 $i$ ,第一项为 $j$ 的前缀和。
$$
f[i][j][k]+=P\times (n-j+1)\times i-\sum_{l=1}^{l\le i}(g1[l-i+n][i-j]-g1[l-i+j-1][i-j])
$$
然后就是类似之前的前缀和
$$
f[i][j][k]+=P\times (n-j+1)\times i-g2[n+i-j][j-i]+g2[n-j][j-i]+g2[i-1][j-i]
$$
真可怕......
以下代码:
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=505,p=1e9+7; int n,k,a[N],f[N][N],A[N][N],B[N][N],C[N][N],inv; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int mu(int x,int y){ return (x+y>=p)?x+y-p:x+y; } il int ksm(LL a,int y){ LL b=1; while(y){ if(y&1)b=b*a%p; a=a*a%p;y>>=1; } return b; } int main() { n=read();k=read();inv=ksm(n*(n+1)/2,p-2); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++)f[i][j]=a[i]>a[j]; while(k--){ for(int j=1;j<=n;j++){ for(int i=1;i<j;i++)A[i][j]=mu(A[i-1][j],f[i][j]); for(int i=1;i<j;i++)A[i][j]=mu(A[i-1][j],A[i][j]); } for(int i=n;i;i--){ for(int j=n;j>i;j--)B[i][j]=mu(f[i][j],B[i][j+1]); for(int j=n;j>i;j--)B[i][j]=mu(B[i][j],B[i][j+1]); } for(int j=0;j<n;j++){ for(int i=1;i<=n-j;i++)C[i][j]=mu(C[i-1][j],f[i][i+j]); for(int i=1;i<=n-j;i++)C[i][j]=mu(C[i][j],C[i-1][j]); } for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ f[i][j]=1ll*f[i][j]*mu(1ll*i*(i-1)/2%p,mu(1ll*(n-j)*(n-j+1)/2%p,1ll*(j-i-1)*(j-i)/2%p))%p; f[i][j]=mu(f[i][j],mu(A[j-1][j],p-mu(A[j-i-1][j],A[i-1][j]))); f[i][j]=mu(f[i][j],mu(B[i][i+1],p-mu(B[i][j+1],B[i][n+2-j+i]))); f[i][j]=mu(f[i][j],mu(1ll*i*(n-j+1)%p,mu(C[n-j][j-i],mu(C[i-1][j-i],p-C[n+i-j][j-i])))); f[i][j]=1ll*f[i][j]*inv%p; } } } int ans=0; for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)ans=mu(ans,f[i][j]); printf("%d\n",ans); return 0; }