P6076 [JSOI2015] 染色问题 分析
题目概述
有 \(n\times m\) 的棋盘,现在需要涂 \(k\) 种颜色上去,需要满足:
- 每一行至少有一个格子被涂色。
- 每一列至少有一个格子被涂色。
- \(k\) 种颜色必须都在这个棋盘上出现。
数据范围:\(1\leq n,m,k\leq 400\)。
分析
经典题目,记录一下。
多重容斥的经典题目。
我们考虑枚举 \(i,j,t\) 表示至少有 \(i\) 行格子没被涂色,至少有 \(k\) 行格子没被涂色,至少没用 \(k\) 种颜色。
所以说:
\[ans=\sum_{i=0}^n\sum_{j=0}^m\sum_{t=0}^k(-1)^{i+j+k}C_{n}^iC_{m}^jC_{k}^t F(i,j,t)
\]
其中 \(F(i,j,t)\) 表示这种情况下的方案数是多少。
那么对于剩下的行数、列数的格子有 \((n-i)\times (m-j)\) 个。
每个格子有两种选择:
- 不被涂色。
- 涂成剩下 \((k-t)\) 种颜色下的一种。
也就是说,每个格子有 \((k-t+1)\) 种选择,所以:
\[F(i,j,t)=(k-t+1)^{(n-i)\times (m-j)}
\]
那么就直接这样做就行了。
代码
时间复杂度 \(\mathcal{O}(nmc)\)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define int long long
#define N 405
using namespace std;
const int mod = 1e9 + 7;
int qpow(int a,int b) {
int res = 1;
while(b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int jc[N],inv[N];
int C(int a,int b) {
if (a < 0 || b < 0 || a < b) return 0;
return jc[a] * inv[b] % mod * inv[a - b] % mod;
}
signed main(){
jc[0] = jc[1] = inv[0] = inv[1] = 1;
for (int i = 2;i < N;i ++) jc[i] = jc[i - 1] * i % mod,inv[i] = (mod - mod / i) * inv[mod % i] % mod;
for (int i = 2;i < N;i ++) inv[i] = inv[i - 1] * inv[i] % mod;
int ans = 0,n,m,k;
cin >> n >> m >> k;
for (int i = 0;i <= n;i ++)
for (int j = 0;j <= m;j ++)
for (int t = 0;t <= k;t ++) {
int xs = ((i + j + t & 1) ? -1 : 1);
ans = (ans + (xs * C(n,i) * C(m,j) % mod * C(k,t) % mod * qpow((k - t + 1),(n - i) * (m - j)) % mod + mod) % mod) % mod;
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号