BZOJ 4487 染色问题

题意:
给定(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();
}
原文地址:https://www.cnblogs.com/cjc030205/p/11638079.html