Description
给定一个长度为n的排列a[]进行k次操作,每次等概率选择一个连续区间进行翻转操作,问k次操作后序列逆序对的期望数量
n
≤
500
,
  
k
≤
50
n\le500,\;k\le50
n≤500,k≤50
Solution
大力讨论题,之前做过一个k次操作是给定的,感觉差不多吧
一个非常naive的dp就是
f
[
i
,
j
,
k
]
f[i,j,k]
f[i,j,k]表示k次操作,i<j的概率,然后我们暴力枚举所有可能的操作区间转移,总的复杂度是
O
(
n
4
k
)
O(n^4k)
O(n4k)的,理论上有39p(选手实现的差异产生了分数的区别
转移如下:
- r < i 或 l > j 或 i < l ≤ r < j r<i或l>j或i<l\le r<j r<i或l>j或i<l≤r<j,这三种情况无论怎么翻转都不影响答案
- l ≤ i ≤ r < j l\le i\le r< j l≤i≤r<j,这种情况第i个数变成了第 r + l − i r+l-i r+l−i 个
- i < l ≤ j ≤ r i<l\le j\le r i<l≤j≤r,这种情况第j个数变成了第 r + l − j r+l-j r+l−j 个
- l ≤ i < j ≤ r l\le i<j\le r l≤i<j≤r,这种情况i和j对应都变了
考虑转移1怎么优化,系数就是不包含i和j两个位置的子区间数量,这样转移就是O(1)的了
考虑转移2怎么优化,我们实际上在求这个东西
∑
l
=
1
i
∑
r
=
i
j
−
1
f
[
r
+
l
−
i
,
j
,
k
−
1
]
\sum\limits_{l=1}^{i}\sum\limits_{r=i}^{j-1}f[r+l-i,j,k-1]
l=1∑ir=i∑j−1f[r+l−i,j,k−1],那么就是两次前缀和了
转移3和2是类似的
然后我做到这就不会了。。。
转移4实际上在求这个东西
∑
l
=
1
i
∑
r
=
j
n
f
[
r
+
l
−
j
,
r
+
l
−
i
,
k
−
1
]
\sum\limits_{l=1}^i\sum\limits_{r=j}^n{f[r+l-j,r+l-i,k-1]}
l=1∑ir=j∑nf[r+l−j,r+l−i,k−1]
注意到这里两维的差是常数,那么令
g
[
i
,
j
]
=
f
[
i
,
i
+
j
,
k
−
1
]
g[i,j]=f[i,i+j,k-1]
g[i,j]=f[i,i+j,k−1],于是变成求
∑
l
=
1
i
∑
r
=
j
n
g
[
r
+
l
−
j
,
j
−
i
]
\sum\limits_{l=1}^i\sum\limits_{r=j}^n{g[r+l-j,j-i]}
l=1∑ir=j∑ng[r+l−j,j−i],就和上面一样了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
typedef long long LL;
const int MOD=1000000007;
const int ny2=(MOD+1)/2;
const int N=505;
LL s1[N][N],s2[N][N],s3[N][N];
LL f[51][N][N],g[N][N],wjp;
int a[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
LL ksm(LL x,LL dep) {
LL res=1; x%=MOD;
for (;dep;dep>>=1) {
(dep&1)?(res=res*x%MOD):0;
x=x*x%MOD;
}
return res;
}
void upd(LL &x,LL y) {
x+=y; (x>=MOD)?(x-=MOD):0;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read(),m=read();
rep(i,1,n) a[i]=read();
rep(i,1,n) rep(j,i+1,n) f[0][i][j]=(a[i]>a[j]);
wjp=ksm((n+1)*n/2,MOD-2);
rep(k,1,m) {
rep(j,1,n) {
rep(i,1,j-1) s1[i][j]=(s1[i-1][j]+f[k-1][i][j])%MOD;
rep(i,1,j-1) upd(s1[i][j],s1[i-1][j]);
}
rep(i,1,n) {
rep(j,i+1,n) s2[i][j]=(s2[i][j-1]+f[k-1][i][j])%MOD;
rep(j,i+1,n) upd(s2[i][j],s2[i][j-1]);
rep(j,i+1,n) f[k][i][j]=f[k-1][i][j]*ny2%MOD*(n*n+2*i*i+2*j*j+n-2*j-2*n*j-2*i*j)%MOD;
}
rep(j,0,n) {
rep(i,1,n-j) s3[i][j]=(s3[i-1][j]+f[k-1][i][i+j])%MOD;
rep(i,1,n-j) upd(s3[i][j],s3[i-1][j]);
}
rep(i,1,n) rep(j,i+1,n) {
upd(f[k][i][j],(s2[i][n]-s2[i][n-j+i]-s2[i][j-1]+s2[i][i])%MOD+MOD);
upd(f[k][i][j],(s1[j-1][j]-s1[j-i-1][j]-s1[i-1][j])%MOD+MOD);
upd(f[k][i][j],MOD-(s3[n-j+i][j-i]-s3[n-j][j-i]-s3[i-1][j-i])%MOD);
upd(f[k][i][j],i*(n-j+1));
f[k][i][j]=(f[k][i][j]*wjp%MOD+MOD)%MOD;
}
}
LL ans=0;
rep(i,1,n) rep(j,i+1,n) upd(ans,f[m][i][j]);
printf("%lld\n", ans);
return 0;
}