题意
给出一个1~N的排列P,进行K次操作,每次等概率的选取一段区间(从所有
n
(
n
+
1
)
2
\frac{n(n+1)}{2}
2n(n+1)中选)翻转
求K次操作后的逆序对期望个数
题解
定义d(i,j,k)为k次操作后,
P
i
>
P
j
P_i>P_j
Pi>Pj的概率
暴力枚举区间转移是n^2的,
我们可以将区间[l,r]分类
1.[l,r]与[i,j]无交集或[i,j]包含了[l,r]:从
d
(
i
,
j
,
k
−
1
)
d(i,j,k-1)
d(i,j,k−1)转移
2.[l,r]中包含i而不包含j:从
d
(
l
+
r
−
i
,
j
,
k
−
1
)
d(l+r-i,j,k-1)
d(l+r−i,j,k−1)转移
3.[l,r]中包含j而不包含i:从
d
(
i
,
l
+
r
−
j
,
k
−
1
)
d(i,l+r-j,k-1)
d(i,l+r−j,k−1)转移
4.[l,r]中包含[i,j]:从
d
(
l
+
r
−
i
,
l
+
r
−
j
,
k
−
1
)
d(l+r-i,l+r-j,k-1)
d(l+r−i,l+r−j,k−1)转移
下面再考虑优化
第一类转移很好办,直接算出[1,i-1],[i,j],[j+1,r]的区间个数,可以预处理也可以直接等差数列求和
第二类转移就要稍微麻烦些了 (k我就懒得写了)
首先第二类转移的贡献f
f
=
∑
l
=
1
i
∑
r
=
i
j
−
1
d
(
l
+
r
−
i
,
j
)
=
∑
l
=
1
i
∑
r
=
0
j
−
i
−
1
d
(
l
+
r
,
j
,
k
)
f=\sum_{l=1}^i\sum_{r=i}^{j-1}d(l+r-i,j)=\sum_{l=1}^i\sum_{r=0}^{j-i-1}d(l+r,j,k)
f=l=1∑ir=i∑j−1d(l+r−i,j)=l=1∑ir=0∑j−i−1d(l+r,j,k)
那么第一维是个连续的和,我们考虑前缀和优化(尽管光看这一步并没有时间复杂度上的优化),令
S
(
n
,
j
)
=
∑
i
=
1
n
d
(
i
,
j
)
S(n,j)=\sum_{i=1}^nd(i,j)
S(n,j)=∑i=1nd(i,j),那么
f
=
∑
l
=
1
i
S
(
l
+
j
−
i
−
1
,
j
)
−
S
(
l
−
1
,
j
)
f=\sum_{l=1}^iS(l+j-i-1,j)-S(l-1,j)
f=l=1∑iS(l+j−i−1,j)−S(l−1,j)
欸,似乎又是个连续的和(其实不化简也行),我们可以再次前缀和优化,令
S
1
(
n
,
j
)
=
∑
i
=
1
n
S
(
i
,
j
)
S_1(n,j)=\sum_{i=1}^nS(i,j)
S1(n,j)=∑i=1nS(i,j)那么
f
=
S
1
(
j
−
1
,
j
)
−
S
1
(
j
−
i
−
1
,
j
)
−
S
1
(
i
−
1
,
j
)
f=S_1(j-1,j)-S_1(j-i-1,j)-S_1(i-1,j)
f=S1(j−1,j)−S1(j−i−1,j)−S1(i−1,j)
其实后面还有一个
+
S
1
(
0
,
j
)
+S_1(0,j)
+S1(0,j)
是不是所有形如 ∑ i = 1 n ∑ j = 1 m d ( i + j ) \sum_{i=1}^n\sum_{j=1}^md(i+j) ∑i=1n∑j=1md(i+j)的都能够用前缀和优化呢
似乎是这样的呢
那么类似的,我们可以推出第三类转移的贡献
令
S
(
p
,
q
)
=
∑
j
=
1
q
d
(
p
,
j
)
S(p,q)=\sum_{j=1}^qd(p,j)
S(p,q)=∑j=1qd(p,j),然后把这个S再求个和得到
S
2
S_2
S2
那么
f
=
S
2
(
i
,
n
)
−
S
2
(
i
,
i
+
n
−
j
)
−
S
2
(
i
,
j
−
1
)
+
S
2
(
i
,
i
−
1
)
f=S_2(i,n)-S_2(i,i+n-j)-S_2(i,j-1)+S_2(i,i-1)
f=S2(i,n)−S2(i,i+n−j)−S2(i,j−1)+S2(i,i−1)
第四类转移也是类似的
f
=
∑
l
=
1
i
∑
r
=
j
n
d
(
l
+
r
−
i
,
l
+
r
−
j
)
f=\sum_{l=1}^i\sum_{r=j}^{n}d(l+r-i,l+r-j)
f=l=1∑ir=j∑nd(l+r−i,l+r−j)
我们令
g
(
i
,
j
)
=
d
(
i
,
i
+
j
)
g(i,j)=d(i,i+j)
g(i,j)=d(i,i+j)
注意此处j的意义不同!
那么
f
=
∑
l
=
1
i
∑
r
=
i
+
j
n
g
(
l
+
r
−
i
,
−
j
)
=
∑
l
=
1
i
S
(
l
+
n
−
i
,
−
j
)
−
S
(
l
+
j
−
1
,
−
j
)
=
S
3
(
n
,
−
j
)
−
S
3
(
n
−
i
,
−
j
)
−
S
3
(
i
+
j
−
1
,
−
j
)
+
S
3
(
j
−
1
,
−
j
)
f=\sum_{l=1}^i\sum_{r=i+j}^ng(l+r-i,-j)=\sum_{l=1}^iS(l+n-i,-j)-S(l+j-1,-j)=S_3(n,-j)-S_3(n-i,-j)-S_3(i+j-1,-j)+S_3(j-1,-j)
f=l=1∑ir=i+j∑ng(l+r−i,−j)=l=1∑iS(l+n−i,−j)−S(l+j−1,−j)=S3(n,−j)−S3(n−i,−j)−S3(i+j−1,−j)+S3(j−1,−j)
-j的处理我们平移个2就好了
最后再乘上总区数的逆元即可
那么最终的答案就是
∑
i
=
1
n
∑
j
=
i
+
1
n
d
(
i
,
j
,
K
)
\sum_{i=1}^n\sum_{j=i+1}^nd(i,j,K)
∑i=1n∑j=i+1nd(i,j,K)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N=1005;
const ll mod=1e9+7;
ll ksm(ll x,ll y){
ll res=1;
while(y){
if(y&1)
res=1ll*res*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return res;
}
ll d[N][N],f[N][N];
ll s1[N][N],s2[N][N],s3[N][N];
ll s0[N];
int p[N];
int n,K;
inline ll add(ll x,ll y){
ll res=x+y;
res=(res%mod+mod)%mod;
return res;
}
inline ll mul(ll x,ll y){
ll res=1ll*x*y%mod;
return res;
}
void calc(){
for(ll i=1;i<=n;i++)
for(ll j=i+1;j<=n;j++)
d[j][i]=add(1,-d[i][j]);
for(ll j=1;j<=n;j++){
for(ll i=1;i<=n;i++)
s1[i][j]=add(s1[i-1][j],d[i][j]);
for(ll i=1;i<=n;i++)
s1[i][j]=add(s1[i][j],s1[i-1][j]);
}
for(ll i=1;i<=n;i++){
for(ll j=1;j<=n;j++)
s2[i][j]=add(s2[i][j-1],d[i][j]);
for(ll j=1;j<=n;j++)
s2[i][j]=add(s2[i][j],s2[i][j-1]);
}
for(ll i=1;i<=n;i++){
for(ll j=1;j<=n;j++)
s3[i][j-i+n]=add(s3[i-1][j-i+n],d[i][j]);
}
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
s3[i][j-i+n]=add(s3[i][j-i+n],s3[i-1][j-i+n]);
}
void Debug(){
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++){
printf("d[%lld][%lld]=%lld\n",i,j,d[i][j]);
}
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++){
printf("s1[%lld][%lld]=%lld\n",i,j,s1[i][j]);
}
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++){
printf("s2[%lld][%lld]=%lld\n",i,j,s2[i][j]);
}
for(ll i=1;i<=n;i++)
for(ll j=-i+1;i+j<=n;j++){
printf("s3[%lld][%lld]=%lld\n",i,j,s3[i][j+n]);
}
}
int main()
{
scanf("%d%d",&n,&K);
for(ll i=1;i<=n;i++)
scanf("%d",&p[i]);
for(ll i=1;i<=n;i++)
s0[i]=s0[i-1]+i;
ll inv=ksm(s0[n],mod-2);
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
d[i][j]=(p[i]>p[j]);
for(ll k=1;k<=K;k++){
calc();
for(ll i=1;i<=n;i++)
for(ll j=i+1;j<=n;j++){
d[i][j]=mul(d[i][j],s0[i-1]+s0[j-i-1]+s0[n-j]);
d[i][j]=add(d[i][j],s1[j-1][j]-s1[j-i-1][j]-s1[i-1][j]);
d[i][j]=add(d[i][j],s2[i][n]-s2[i][i+n-j]-s2[i][j-1]+s2[i][i-1]);
int z=j-i;
d[i][j]=add(d[i][j],s3[n][-z+n]-s3[n-i][-z+n]-s3[i+z-1][-z+n]+s3[z-1][-z+n]);
}
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++){
d[i][j]=mul(d[i][j],inv);
}
//Debug();
}
//Debug();
ll ans=0;
for(ll i=1;i<=n;i++)
for(ll j=i+1;j<=n;j++)
ans=add(ans,d[i][j]);
printf("%lld\n",ans);
}