codeforce#1228E Another Filling the Grid

题意:
给出 N , K ( 1 ≤ N ≤ 250 , 1 ≤ K ≤ 1 0 9 ) N,K(1\leq N \leq250,1\leq K \leq 10^9) N,K(1N250,1K109),求 N ∗ N N*N NN矩阵每行每列至少有一个 1 1 1的方案数(每行至少有一个1,每列至少也有一个1)
题解:
d p [ i ] [ j ] dp[i][j] dp[i][j]表示在 i ∗ N i*N iN这个子矩阵中已经有 j j j列是至少有一个1的方案数,现在进行状态转移:
已经有 j j j列有1,那么还有 N − j N-j Nj列没有1,在 N − j N-j Nj列中选出 k k k列,把这 k k k列选中为1,其他 N − j − k N-j-k Njk列的方案数就是 ( K − 1 ) N − j − k (K-1)^{N-j-k} (K1)Njk
这里还有要注意的一点,如果 k = 0 k=0 k=0?那么这行就有可能用部分方案数是零个1,这是不符合条件的,因此需要减掉
总结: d p [ i + 1 ] [ j + k ] + = d p [ i ] [ k ] ∗ C N − j k ∗ K j ∗ ( K − 1 ) N − j − k dp[i+1][j+k]+=dp[i][k]*C_{N-j}^k*K^j*(K-1)^{N-j-k} dp[i+1][j+k]+=dp[i][k]CNjkKj(K1)Njk
k = 0 k=0 k=0时需要处理:
d p [ i + 1 ] [ j + k ] − = d p [ i ] [ j ] ∗ ( K − 1 ) N dp[i+1][j+k]-=dp[i][j]*(K-1)^N dp[i+1][j+k]=dp[i][j](K1)N

整合下两个转移方程

d p [ i + 1 ] [ j + k ] + = d p [ i ] [ j ] ∗ ( C N − j k ∗ K j ∗ ( K − 1 ) N − j − k − ( k = = 0 ) ∗ ( K − 1 ) N ) dp[i+1][j+k]+=dp[i][j]*(C_{N-j}^k*K^j*(K-1)^{N-j-k}-(k==0)*(K-1)^N) dp[i+1][j+k]+=dp[i][j](CNjkKj(K1)Njk(k==0)(K1)N)
code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int maxn=255;
ll fac[maxn],inv[maxn],power_k[maxn],power_k_1[maxn],dp[maxn][maxn];
ll fast(ll x,ll y=mod-2){
    ll ans=1;
    while(y){
        if(y&1)ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans;
}
void init(int n,int k){
    fac[0]=1;power_k[0]=power_k_1[0]=1;
    for(int i=1;i<=n;i++){
        fac[i]=fac[i-1]*i%mod;
        power_k[i]=power_k[i-1]*k%mod;
        power_k_1[i]=power_k_1[i-1]*(k-1)%mod;
    }
    inv[n]=fast(fac[n]);
    for(int i=n-1;i>=0;i--)
        inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(int n,int m){
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
    int n,K;
    scanf("%d%d",&n,&K);
    init(n,K);
    dp[0][0]=1;
    for(int i=0;i<n;i++){
        for(int j=0;j<=n;j++){
            if(dp[i][j]==0)continue;
            for(int k=0;k<=n-j;k++){
                dp[i+1][j+k]=(dp[i+1][j+k]+dp[i][j]*(C(n-j,k)*power_k[j]%mod*power_k_1[n-j-k]%mod-(k==0)*power_k_1[n]+mod)%mod)%mod;
            }
        }
    }
    cout<<dp[n][n]<<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Macarons_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值