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;
}
posted @ 2020-09-22 16:17  jasony_sam  阅读(153)  评论(0编辑  收藏  举报