CF1151F Sonya and Informatics
Solution
令 \(c\) 为序列中 \(0\) 的个数,那么想排完是不降的,那么前面必须是 \(c\) 个 \(0\) ,后面 \(n-c\) 个 \(1\)。
那么可以轻而易举的设 \(f[i][j]\) 表示经过 \(i\) 次操作后,前 \(c\) 个数中有 \(j\) 个 \(0\) 的方案数,则答案为 \(\dfrac{f[k][c]}{\sum f[k][i]}\) 。
(其中前 \(c\) 个数中有 \(c-j\) 个 \(1\) ,后面 \(n-c\) 个数中有 \(c-j\) 个 \(0\) ,有 \(n-2\cdot c+j\) 个 \(1\) )
初始状态:设初始序列中 \(0\) 的个数为 \(cnt\) ,那么 \(f[0][cnt]=1\) 其余为 \(0\)
那么状态转移方程也是不难滴:
\[f[i][j]+=f[i-1][j]\cdot(\dfrac{c(c-1)}{2}+\dfrac{(n-c)(n-c-1)}{2}+j(c-j)+(c-j)(n-2\cdot c+j))
\]
\(\dfrac{c(c-1)}2\) 为前 \(c\) 个随便交换, \(\dfrac{(n-c)(n-c-1)}2\) 为后 \(n-c\) 个随便交换, \(j(c-j)\) 为前面的 \(0\) 和后面的 \(0\) 交换,\((c-j)(n-2\cdot c+j)\) 为前面的 \(1\) 和后面的 \(1\) 交换。
\[f[i][j]+=f[i-1][j-1]\cdot(c-j+1)^2
\]
\((c-j+1)^2\) 为把前面的 \(1\) 和后面的 \(0\) 交换。
\[f[i][j]+=f[i-1][j+1]\cdot(j+1)(n-2\cdot c+j+1)
\]
\((j+1)(n-2\cdot c+j+1)\) 为把前面的 \(0\) 和后面的 \(1\) 交换。
我们会发现第 \(i\) 层和第 \(i-1\) 层是连着的,然后就矩阵优化。
时间复杂度 \(O(n^3\log k)\) 。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=101,mod=1e9+7;
int n,k,a[N],c,cnt;//c是总共0的数量 cnt是初始状态前c个数有几个0
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
return x*f;
}
inline int add(int a,int b){return a+b<mod?a+b:a+b-mod;}
inline int sub(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline fpow(int a,int b){
int res=1;
while(b){
if(b&1) res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
struct matrix{
int a[N][N];
matrix(){memset(a,0,sizeof(a));}
matrix operator * (const matrix &x) const {
matrix ans;
for(int i=0;i<=c;i++)
for(int j=0;j<=c;j++)
for(int k=0;k<=c;k++)
ans.a[i][j]=add(ans.a[i][j],mul(a[i][k],x.a[k][j]));
return ans;
}
}A,I,ans;
matrix Fpow(matrix a,int b){
matrix res;
for(int i=0;i<=c;i++) res.a[i][i]=1;
while(b){
if(b&1) res=res*a;
a=a*a;
b>>=1;
}
return res;
}
int main(){
n=read();k=read();
for(int i=1;i<=n;i++)
a[i]=read(),c+=!a[i];
for(int i=1;i<=c;i++) cnt+=!a[i];
A.a[cnt][0]=1;
for(int i=0;i<=c;i++){
I.a[i][i]=(1ll*c*(c-1)/2+1ll*(n-c)*(n-c-1)/2+1ll*i*(c-i))%mod;
if(i>=2*c-n) I.a[i][i]=add(I.a[i][i],mul(c-i,n-2*c+i));
if(i) I.a[i][i-1]=mul(c-i+1,c-i+1);
if(i!=c&&i+1>=2*c-n) I.a[i][i+1]=mul(i+1,n-2*c+i+1);
}
ans=Fpow(I,k)*A;
int sum=0;
for(int i=0;i<=c;i++) sum=add(sum,ans.a[i][0]);
sum=mul(fpow(sum,mod-2),ans.a[c][0]);
printf("%d\n",sum);
return 0;
}