题目描述
在一个m行n列的棋盘里放一些彩色的棋子,使得每个格子最多放一个棋子,且不同
颜色的棋子不能在同一行或者同一列。有多少祌方法?
输入输出格式
输入格式:
输入第一行为两个整数n, m, c,即行数、列数和棋子的颜色数。第二行包含c个正整数,即每个颜色的棋子数。所有颜色的棋子总数保证不超过nm。
输出格式:
输出仅一行,即方案总数除以 1,000,000,009的余数。
输入输出样例
输入样例#1: 复制
4 2 2
3 1
输出样例#1: 复制
8
说明
N,M<=30 C<=10 总棋子数<=250
题解
组合计数没想出来==
但是这种题想明白了也不难啊><
可以发现同一行/列最多只能有一种颜色的棋子,
所以不需要考虑棋子具体放在哪里
所以可以设(f[i][j][k])表示已经放完前(k)种颜色的棋子,已经占满了(i)行(j)列的方案数
那么(f[i][j][k] = sum_{a=0}^{i}sum_{b=0}^{j}{f[a][b][k-1]*C(n-a,i-a)*C(m-b,j-b)*(用num[k]个棋子放在这些(i-a)*(j-b)个格子且每行每列都有棋子的方案数)})
答案就是(sum_{i=1}^{n}sum_{j=1}^{m}{f[i][j][c]})
我们发现用(num[k])个棋子放在这些((i-a)*(j-b))个格子的方案数能很快的求出
但是有一个限制是每行每列都要有棋子,所以就不能直接计算了
可以设一个(g[i][j][k])表示用(k)个棋子填满(i)行(j)列且每行每列都有棋子
那么可以简单的容斥一下,(g[i][j][k]=C(i*j,k)-sum_{a=1}^{i}sum_{b=1}^{i}{g[a][b][k] * C(i,a) * C(j,b) * [a != i || b != j]})
这样就可以求出来了
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
# define int long long
const int M = 35 ;
const int N = 2005 ;
const int mod = 1e9 + 9 ;
using namespace std ;
int n , m , e , Ans , num[M] , f[M][M][N] , g[M][M][N] , c[N][N] ;
# undef int
int main() {
# define int long long
scanf("%lld%lld%lld",&n,&m,&e) ;
for(int i = 1 ; i <= e ; i ++) scanf("%lld",&num[i]) ;
c[0][0] = 1 ;
for(int i = 1 ; i <= 2000 ; i ++) {
c[i][0] = 1 ;
for(int j = 1 ; j <= i ; j ++)
c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod ;
}
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= m ; j ++)
for(int k = max(i , j) ; k <= i * j ; k ++) {
g[i][j][k] = c[i * j][k] ;
for(int a = 1 ; a <= i ; a ++)
for(int b = 1 ; b <= j ; b ++) {
if(a * b < k || (a == i && b == j)) continue ;
g[i][j][k] = (g[i][j][k] - g[a][b][k] * c[i][a] % mod * c[j][b] % mod + mod) % mod ;
}
}
f[0][0][0] = 1 ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= m ; j ++) {
for(int k = 1 ; k <= e ; k ++) {
if(i * j < num[k]) continue ;
for(int a = 0 ; a <= i ; a ++)
for(int b = 0 ; b <= j ; b ++)
if((i - a) * (j - b) >= num[k])
f[i][j][k] = (f[i][j][k] + f[a][b][k - 1] * c[n - a][i - a] % mod * c[m - b][j - b] % mod * g[i - a][j - b][num[k]] % mod + mod) % mod ;
}
Ans = (Ans + f[i][j][e]) % mod ;
}
printf("%lld
",(Ans % mod + mod) % mod) ;
return 0 ;
}