「JSOI2015」染色问题

「JSOI2015」染色问题

传送门

虽然不是第一反应,不过还是想到了要容斥。

题意转化:需要求满足 \(N + M + C\) 个条件的方案数。

然后我们就枚举三个数 \(i, j, k\) ,表示当前方案中,至少不用 \(k\) 种颜色,至少不涂 \(i\) 行、至少不涂 \(j\) 列。

然后直接组合数算(式子不难看懂),最后容斥即可。

那么写出来就是:

\[ans = \sum_{i = 0}^n \sum_{j = 0}^m \sum_{k = 0}^c (-1)^{i + j + k} (c - k + 1)^{(n - i) \times (m - j)} {n \choose i}{m \choose j}{c \choose k} \]

参考代码:

#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}
 
const int _ = 404, p = 1e9 + 7;
  
int n, m, c, N, x, ans, C[_][_], pow[_][_ * _];
 
int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    read(n), read(m), read(c);
    if (N < n) N = n; if (N < m) N = m; if (N < c) N = c;
    for (rg int i = 0; i <= N; ++i) C[i][0] = 1;
    for (rg int i = 1; i <= N; ++i)
    	for (rg int j = 1; j <= i; ++j)
	        C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % p;
    for (rg int i = 1; i <= c + 1; ++i) pow[i][0] = 1;
    for (rg int i = 1; i <= c + 1; ++i)
	    for (rg int j = 1; j <= n * m; ++j)
	        pow[i][j] = 1ll * i * pow[i][j - 1] % p;
    for (rg int i = 0; i <= n; ++i)
	    for (rg int j = 0; j <= m; ++j)
	        for (rg int k = 0; k <= c; ++k) {
		        x = (i + j + k) & 1 ? -1 : 1;
		        ans = (ans + 1ll * x * pow[c - k + 1][(n - i) * (m - j)] % p * C[n][i] % p * C[m][j] % p * C[c][k] % p) % p;
        }
    printf("%d\n", (ans % p + p) % p);
    return 0;
}
posted @ 2020-02-14 22:52  Sangber  阅读(152)  评论(0编辑  收藏  举报