Description
Analysis
考虑约束:
- 每行每列至少一个棋子
- 每种颜色的棋子都要有
先不考虑约束2,对于约束1,我们发现直接做很难做,考虑正难则反着做呗
我们尝试构造出不满足约束1却满足约束2的情况,显然就是我们人为规定一些行列一个棋子都没有,其他格子乱选的且满足约束2
这样会有重复,所以要容斥计算
写成数学式,就是
Ans=∑i=0m∑j=0n(−1)i+j∗Cim∗Cjn∗???
???是什么,是其他格子乱选的且满足约束2的方案数
不妨将没有颜色设为第c+1种颜色,那么第c+1种颜色可有可无。
方案数就是将剩余棋盘中的t个格子(t=(m-i)*(n-j))放到c个集合的方案数+放到c+1个集合的方案数
这东西就是
第二类Stirling数
St[i][j]
表示i个元素组成j个集合(不为空)的方案数
显然
St[i][j]=St[i−1][j]∗j+St[i−1][j−1]
所以
???=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;
}