CF1151F Sonya and Informatics(dp+矩阵快速幂)

这题设计二维状态f[][]表示前i个里面有几个0,假设数列中总共有cnt个0最后答案就是操作k次后前i个里面有cnt个0/所有情况

因为k十分巨大,所以考虑使用矩阵快速幂加速dp

对于矩阵状态的设计,就是看看转移状态,发现转移状态只是一个常数,因此列出矩阵后做一遍快速幂即可

 

#include<bits/stdc++.h>
#define getsz(p) (p?p->sz:0)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=200;
int pow_mod(int x,int i) {
    int res=1;
    while(i){
        if(i&1) res=(ll)res*x%mod;
        x=(ll)x*x%mod;
        i>>=1;
    }
    return res;
}
int n,k,a[N];
int cnt;
struct node{
    int a[N][N];
    node(){memset(a,0,sizeof(a));}
}s,t;
node operator *(node a,node b) {
    node tmp;
    for(int i=0;i<=cnt;i++) {
        for(int j=0;j<=cnt;j++) {
            for(int k=0;k<=cnt;k++) {
                tmp.a[i][j]=((ll)tmp.a[i][j]+(ll)a.a[i][k]*b.a[k][j]%mod)%mod;
            }
        }
    }
    return tmp;
}
node matrix_pow(node a,int i) {
    node b;
    for(int i=0;i<=cnt;i++) b.a[i][i]=1;
    while(i) {
        if(i&1) b=b*a;
        a=a*a;
        i>>=1;
    }
    return b;
}
int main() {
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i],cnt+=(a[i]==0);
    int num=0;
    for(int i=1;i<=cnt;i++) num+=(a[i]==0);
    s.a[0][num]=1;
    for(int i=0;i<=cnt;i++) {
        if(i!=0) t.a[i-1][i]=1ll*(cnt-(i-1))*(cnt-(i-1))%mod;
        t.a[i][i]=1ll*(1ll*i*(cnt-i)%mod+1ll*(cnt-i)*(n-cnt-cnt+i))%mod;
        t.a[i][i]=(t.a[i][i]+1ll*cnt*(cnt-1)/2%mod)%mod;
        t.a[i][i]=(t.a[i][i]+1ll*(n-cnt)*(n-cnt-1)/2%mod)%mod;
        if(i!=cnt) t.a[i+1][i]=1ll*(i+1)*(n-cnt-cnt+i+1)%mod;
    }
    t=matrix_pow(t,k);
    s=s*t;
    int ans=s.a[0][cnt];
    int tot=0;
    for(int i=0;i<=cnt;i++)
        tot=((ll)tot+s.a[0][i])%mod;
    ans=((ll)ans*pow_mod(tot,mod-2))%mod;
    cout<<ans<<endl;
    return 0;
}
View Code

 

posted @ 2020-08-06 11:20  朝暮不思  阅读(147)  评论(0编辑  收藏  举报