把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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;
}
posted @ 2025-10-20 08:40  high_skyy  阅读(21)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end