给定 n × n 方格与四个目标数 U R D L,
只允许染边界上的格子,使顶部行、右侧列、底部行、左侧列的黑格数恰好等于这四个数。
难点只有一个:四个角同时属于两条边。
枚举四个角 · 2⁴ = 16 种 · 逐条边验证
边界上的格子分两类:四个角同时属于两条边,其余边界格只属于一条边。
内部格(不在边界上)对四条边的计数都没有贡献,所以永远不必染黑,可以直接忽略。 于是整个问题只剩下 4 个角 + 4×(n−2) 个"边中间格"。
边中间格彼此完全独立——染它只影响它所属的那一条边,不牵动任何别的边。 而角一旦被染黑,会同时给两条边各加 1,这才让四条边互相纠缠。
a 属于 顶部 与 左侧;b 属于 顶部 与 右侧;c 属于 底部 与 右侧;d 属于 底部 与 左侧。
结论:只要把 4 个角的状态定死,四条边就彻底解耦,各自独立计算即可。 这就是"枚举 2⁴ = 16 种"的由来。
设四个角是否染黑分别为 a b c d,取值均为 0 或 1。当前实例:n = 5 n − 2 = 3
注意这四个变量是独立取值的,组合数为 2×2×2×2 = 16,
常用一个整数 mask(0 ~ 15)的四个二进制位来表示:a = mask & 1、b = mask >> 1 & 1、c = mask >> 2 & 1、d = mask >> 3 & 1。
a 和 b,已贡献 a + b 个黑格;
中间还剩 n − 2 = 3 个格子,需要补齐 U − (a + b) 个。
b 和 c,已贡献 b + c;中间需补齐 R − (b + c)。
c 和 d,已贡献 c + d;中间需补齐 D − (c + d)。
d 和 a,已贡献 d + a;中间需补齐 L − (d + a)。
有人会问:满足 0 ≤ need ≤ n − 2 就一定能染出来吗?会不会中间格之间有冲突?
不会。因为每条边的中间格只属于这一条边,与其余三条边没有任何公共格子。
所以只要 need 是一个 0 到 n − 2 之间的整数,从这条边的中间格里
任意挑 need 个染黑即可——挑哪几个根本不影响任何计数。
换句话说:need < 0 表示两个角给多了,已经超过目标,无法挽回;
need > n − 2 表示中间格子不够用,塞不下这么多黑格。
这两种情况之外,方案必然存在。
因此"四条不等式同时成立"是充要条件,检查完就可以直接下结论,不需要真的去构造。
枚举 a, b, c, d ∈ {0, 1} 的 16 种组合,对每一种同时检查四条边约束:
存在任一组 (a, b, c, d) 使四条同时成立 → 输出 YES;
16 种全部失败 → 输出 NO。
当 n = 2 时,每条边的中间长度 n − 2 = 0,即整条边就是它的两个角,没有额外的格子可用。
四条不等式全部退化成等式:U = a + b、R = b + c、D = c + d、L = d + a。
也就是说每条边的计数必须完全由角凑出来,多一个少一个都不行。
把 n − 2 = 0 代进统一公式,得到 0 ≤ need ≤ 0,即 need = 0,
与上面的分析完全一致——公式无需为 n = 2 单独改写,这正是它优雅的地方。
mask 从 0 遍历到 15,四个二进制位分别取出 a, b, c, d。need = [U−(a+b), R−(b+c), D−(c+d), L−(d+a)]。need 全部落在 [0, n−2] 内则当前 mask 合法,输出 YES 并结束。need 个格子染黑即可,顺序随意;内部格一律不染。NO。def solve(n, U, R, D, L): mid = n - 2 for mask in range(16): a = mask & 1 b = (mask >> 1) & 1 c = (mask >> 2) & 1 d = (mask >> 3) & 1 need = [U - (a + b), R - (b + c), D - (c + d), L - (d + a)] if all(0 <= x <= mid for x in need): return True return False # 读入 t 个测试用例,逐例输出 YES / NO t = int(input()) for _ in range(t): n, U, R, D, L = map(int, input().split()) print("YES" if solve(n, U, R, D, L) else "NO")
bool solve(int n, int U, int R, int D, int L) { int mid = n - 2; for (int mask = 0; mask < 16; mask++) { int a = mask & 1; int b = (mask >> 1) & 1; int c = (mask >> 2) & 1; int d = (mask >> 3) & 1; int need[4] = {U - (a + b), R - (b + c), D - (c + d), L - (d + a)}; bool ok = true; for (int x : need) if (x < 0 || x > mid) ok = false; if (ok) return true; } return false; } // main 中读入 t 组数据,逐组输出 YES / NO