zoukankan      html  css  js  c++  java
  • [CQOI2011]放棋子

    题目描述

    在一个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 ;
    }
    
  • 相关阅读:
    Codeforces Round 546 (Div. 2)
    Codeforces Round 545 (Div. 2)
    Codeforces Round 544(Div. 3)
    牛客小白月赛12
    Codeforces Round 261(Div. 2)
    Codeforces Round 260(Div. 2)
    Codeforces Round 259(Div. 2)
    Codeforces Round 258(Div. 2)
    Codeforces Round 257 (Div. 2)
    《A First Course in Probability》-chaper5-连续型随机变量-随机变量函数的分布
  • 原文地址:https://www.cnblogs.com/beretty/p/10286872.html
Copyright © 2011-2022 走看看