码迷,mamicode.com
首页 > 其他好文 > 详细

[题解] [CQOI2011] 放棋子

时间:2020-01-15 23:25:25      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:http   其他   计数   ref   play   etc   bin   har   int   

题面

题解

为了练习计数而做

注意到一种颜色占据的行, 列其他的颜色不能放

又考虑到我们并不需要知道哪些行哪些列选了, 只需要知道还有几行几列没选即可

于是有 \(f[i][j][k]\) 代表前 \(i\) 种颜色选完之后, 还有 \(j\) 行没选, \(k\) 列没选的方案数

\(g[i][j][k]\) 代表, \(i\) 个棋子, 放在 \(j\)\(k\) 列中并且没有空行空列的方案数

\(cnt_i\) 代表颜色为 \(i\) 的棋子有几个


\[ \displaystyle g[i][j][k] = \binom{j*k}{i}-\sum_{x=0}^{j}\sum_{y=0 \&\& x*y \geq i}^{k}(-1)^{x + y}\binom{j}{x}\binom{k}{y}\binom{x*y}{i}\\f[i][j][k] = \sum_{x=0}^{x+j \leq n}\sum_{y=0\&\&x*y\geq cnt_i}^{y+k\leq n}f[i - 1][j+x][k+y]\binom{j+x}{x}\binom{k+y}{y}g[x][y][cnt_i] \]
这个简单容斥一下就可以了

然后, 就没了???

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 1005;
const int mod = 1000000009; 
using namespace std;

int n, m, K, cnt[N], c[N][N], f[15][35][35], g[905][35][35], mx, ans; 

template < typename T >
inline T read()
{
    T x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * w; 
}

int main()
{
    n = read <int> (), m = read <int> (), K = read <int> ();
    for(int i = 1; i <= K; i++)
        mx = max(mx, cnt[i] = read <int> ()); 
    for(int i = 0; i <= n * m; i++)
        for(int j = 0; j <= i; j++)
            c[i][j] = (!j ? 1 : (c[i - 1][j - 1] + c[i - 1][j]) % mod);
    for(int i = 1; i <= mx; i++)
        for(int j = 0; j <= n; j++)
            for(int k = 0; k <= m; k++)
                for(int x = 0; x <= j; x++)
                    for(int y = 0; y <= k; y++)
                        if((j - x) * (k - y) >= i)
                            g[i][j][k] = (1ll * g[i][j][k] +
                                          1ll * c[j][x] * c[k][y] % mod
                                          * ((x + y) & 1 ? -1 : 1) * c[(j - x) * (k - y)][i] % mod + mod) % mod; 
    f[0][n][m] = 1;
    for(int k = 1; k <= K; k++)
        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= m; j++)
                for(int x = 0; x + i <= n; x++)
                    for(int y = 0; y + j <= m; y++)
                        if(f[k - 1][i + x][j + y] && x * y >= cnt[k])
                            f[k][i][j] = (1ll * f[k][i][j] +
                                          1ll * f[k - 1][i + x][j + y] * c[i + x][x] % mod
                                              * c[j + y][y] % mod * g[cnt[k]][x][y] % mod) % mod; 
    for(int i = 0; i <= n; i++)
        for(int j = 0; j <= m; j++)
            ans = (1ll * ans + f[K][i][j]) % mod;
    printf("%d\n", ans); 
    return 0; 
}

[题解] [CQOI2011] 放棋子

标签:http   其他   计数   ref   play   etc   bin   har   int   

原文地址:https://www.cnblogs.com/ztlztl/p/12199056.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!