【JZOJ 3892】 放棋子

58 篇文章 0 订阅
37 篇文章 0 订阅

Description

这里写图片描述
这里写图片描述

Analysis

考虑约束:

  1. 每行每列至少一个棋子
  2. 每种颜色的棋子都要有

先不考虑约束2,对于约束1,我们发现直接做很难做,考虑正难则反着做呗
我们尝试构造出不满足约束1却满足约束2的情况,显然就是我们人为规定一些行列一个棋子都没有,其他格子乱选的且满足约束2
这样会有重复,所以要容斥计算
写成数学式,就是

Ans=i=0mj=0n(1)i+jCimCjn???

???是什么,是其他格子乱选的且满足约束2的方案数
不妨将没有颜色设为第c+1种颜色,那么第c+1种颜色可有可无。
方案数就是将剩余棋盘中的t个格子(t=(m-i)*(n-j))放到c个集合的方案数+放到c+1个集合的方案数
这东西就是

第二类Stirling数

St[i][j] 表示i个元素组成j个集合(不为空)的方案数
显然 St[i][j]=St[i1][j]j+St[i1][j1]
所以 ???=St[t][c]c!+St[t][c+1](c+1)!
为什么要乘阶乘,因为将颜色遍号乱换都是不同的方案

Code

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=402;
const ll mo=1e9+7;
ll m,n,c,fac[N],ny[N];
int St[N*N][N];
ll qmi(ll x,ll n)
{
    ll t=1;
    for(;n;n>>=1)
    {
        if(n&1) t=t*x%mo;
        x=x*x%mo;
    }
    return t;
}
ll C(ll m,ll n)
{
    return fac[m]*ny[n]%mo*ny[m-n]%mo;
}
int main()
{
    fac[0]=ny[0]=1;
    fo(i,1,400) fac[i]=fac[i-1]*i%mo,ny[i]=qmi(fac[i],mo-2);
    scanf("%lld %lld %lld",&m,&n,&c);
    St[0][0]=1;
    fo(i,1,m*n)
        fo(j,1,c+1) St[i][j]=((ll)St[i-1][j]*j%mo+St[i-1][j-1])%mo;
    ll ans=0;
    fo(i,0,m)
        fo(j,0,n)
        {
            ll x=C(m,i)*C(n,j)%mo,t=(m-i)*(n-j);
            x=x*((ll)St[t][c]*fac[c]%mo+(ll)St[t][c+1]*fac[c+1]%mo)%mo;
            if((i+j)&1) ans=(ans-x+mo)%mo;
            else ans=(ans+x)%mo;
        }
    printf("%lld",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值