题意:
给定(n imes m)的网格和(c)种颜色,要求每种颜色至少出现一次,每行每列至少有一个格子被染色。
sol:容斥。
每种颜色至少出现一次比较难限制,于是我们考虑限制颜色不出现:
要求的是每种颜色至少出现一次,转成求恰好有0种颜色不出现
设(F(x))表示至少有(x)种颜色不出现,
那么答案即为(sum_{i=0}^c{C_c^i(-1)^iF(i)})
考虑怎么算(F(x))。
至少有(x)种颜色不出现,那么就是至多出现了(c-x)种颜色。
每行每列至少有一个格子被染色,转化成:
恰好(n)行被染色,也就是恰好0行不被染色。
定义(G'(y,c-x))为用(c-x)种颜色的情况下,至少有(y)行不被染色
等价于定义(G(n - y,c-x))为用至多(c-x)种颜色去染色至多(n - y)行
(F(i)=sum_{j=0}^nC_n^i(-1)^iG(n-j,c-i))
现在是(n-y)行(m)列染(c-x)种颜色,可以不染色,但是每列至少有一个被染色
每列((c-x+1)^{n-y}-1)种方案
所以(G(n-y,c-x)=((c-x+1)^{n-y}-1)^m)
所以(ans=sum_{i=0}^csum_{j=0}^n{C_c^iC_n^j(-1)^{i+j}((c-i+1)^{n-j}-1)^m})
复杂度 (nclogm)
#include <cstdio>
#include <cstring>
const int N = 5e2+7;
typedef long long LL;
const LL p = 1e9+7;
inline LL FST(LL b, LL k) {
if (b < 0) b += p;
LL ans = 1LL;
while (k) {
if (k & 1) ans = (ans * b) % p; b = b * b % p, k >>= 1LL;
} return ans;
}
LL fac[N*N]; LL n, m, c; LL C[N][N];
const int lim = 5e2;
void init() {
C[0][0] = 1;
for (int i = 1; i <= lim; i++) {
C[i][0] = 1;
for (int j = 1; j <= lim; j++) {
C[i][j] += C[i - 1][j] + C[i - 1][j - 1];
C[i][j] = C[i][j] >= p ? C[i][j] - p : C[i][j];
}
}
}
void solve1() {
LL ans = 0;
for (int i = 0; i <= c; i++) for (int j = 0; j <= n; j++) {
LL ret = C[c][i] * C[n][j] % p * FST(FST(c - i + 1LL, n - j) - 1LL, m) % p;
ans += (i + j) & 1 ? (-1LL) * ret : ret;
ans = ans >= p ? ans - p : ans;
} printf ("%lld", (ans % p + p) % p);
}
int main() {
scanf("%lld%lld%lld", &n, &m, &c), init(), solve1();
}