给出一个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
#include
#include
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);
}