题单 · 习题解析

洛谷 P1228 地毯填补问题

分治照着 P5461 就能写;真正的门槛是「毯子编号只在原题的图里」—— 而它能从样例反推出来

原题:洛谷 P1228出自 第 2 章 递归的分解思维:汉诺塔与斐波那契 的题单题面本地存档:2026-08-25
⚠ 先自己写一遍,再往下看

这一页不是标准答案,是一条阶梯:把大多数人真实会写出的第一版摆出来, 看它错在哪、慢在哪,再一步一步改。所以它对「已经自己动手撞过一次墙」的人最有用。
还没写过的话,先去写 —— 写出来的哪怕是错的,也比直接看这一页收获大。

0题目原文(本地存了一份)

为什么要在这儿抄一份题面

原题在洛谷上(页头有链接)。别人的网站不归我们管,打不开、改版、题号调整都可能发生。 所以每个解析页都把题面转录一份存在本地,跟着仓库一起进版本库。

转录自洛谷 P1228,日期见页头。两边不一致时信原站。

这道题的题面带两张图(毯子的四种形状、样例解释)—— 两张都存了本地一份public/sol/)。 ★ 其中那张形状图不是装饰,它是分数c = 1/2/3/4 的定义只在图上,文字里一个字都没有。 ⇒ 所以「转录题面」这件事在这道题上必须连图一起转,第 ③ 步还会把它独立验一遍。

题目描述

相传在一个古老的阿拉伯国家里,有一座宫殿。宫殿里有个四四方方的格子迷宫, 国王选择驸马的方法非常特殊,也非常简单:公主就站在其中一个方格子上, 只要谁能用地毯将除公主站立的地方外的所有地方盖上,美丽漂亮聪慧的公主就是他的人了。

公主这一个方格不能用地毯盖住,毯子的形状有所规定,只能有四种选择(如图); 并且每一方格只能用一层地毯,迷宫的大小为 2ᵏ × 2ᵏ 的方形。

原题图 1:四种毯子的形状,从左到右依次编号 1、2、3、4

(原题图 1,存档自洛谷。看清楚这四个形状:1 缺左上、2 缺右上、3 缺左下、4 缺右下 —— 换句话说,编号就是「缺口在哪个角」。)

输入格式:第一行一个整数 k,即迷宫大小为 2ᵏ × 2ᵏ(0 < k ≤ 10); 第二行两个整数 x、y,即公主所在方格的坐标(x 为行坐标,y 为列坐标)。

输出格式:将迷宫填补完整的方案。每一补(行)为 x y c (x、y 为毯子拐角的行坐标和列坐标,c 为使用毯子的形状,具体见原题的图 1, 毯子形状分别用 1、2、3、4 表示,三个数之间用一个空格隔开)。

说明:这道题是 special judge(方案不唯一,只要盖得合法就算对)。 原站列了 spj 的四种报错:① c 越界;② x、y 越界;③ 该位置已被覆盖;④ 该位置从未被覆盖。

输入输出样例

输入

3
3 3

输出

5 5 1
2 2 4
1 1 4
1 4 3
4 1 2
4 4 1
2 7 3
1 5 4
1 8 3
3 6 3
4 8 1
7 2 2
5 1 4
6 3 2
8 1 2
8 4 1
7 7 1
6 6 1
5 8 3
8 5 2
8 8 1

k = 3(8×8),公主在第 3 行第 3 列。上面那段输出是仓库里的 p1228.cpp 真跑出来的, 而且和原站样例逐字节相同 —— 这一点在第 ⑥ 步会变成一条很有用的证据。

样例解释(原题的第二张图,同样存档自洛谷):每个格子上的数字,就是盖住它那块毯子的形状编号; 灰色那格是公主。

原题的样例解释图:8×8 方阵里 21 块毯子各自的形状编号,灰格是公主

1先看清楚:一块毯子长什么样

题面说毯子「只有四种选择」,配了张图 —— 说白了就一句话:

一块毯子 = 2×2 的方块里去掉一格(所以它是个 L 形,占 3 格)。

四种就是「去掉的是哪一格」。下面用 @ 标出题面说的那个拐角(就是输出里的 x y), + 是另外两格,. 是缺口:

   c = 1          c = 2          c = 3          c = 4
   缺左上         缺右上          缺左下         缺右下

   .  +           +  .           +  @           @  +
   +  @           @  +           .  +           +  .

★ 记法只有一句:拐角永远在缺口的对角,而 c 就是缺口在哪个角(1 左上、2 右上、3 左下、4 右下)。

⚠ 这四个编号只在原题图 1 上(第 ⓪ 步那张),文字题面里一个字都没有 —— 所以第 ③ 步会拿样例把它独立验一遍,而不是「看图看出来的」。

2分治的形状:中心那一块毯子

这道题和 P5461 是同一个套路:切成四块。但这里多一层意思, 而且它就是整道题的题眼:

把 2^k x 2^k 切成四个 2^(k-1) x 2^(k-1):
  公主只在其中一块里             -> 这一块可以直接递归(它有一个格子被占住了)
  另外三块是完整的正方形         -> 递归不了!因为「铺满一整块」根本做不到
                                    (3 除不尽 4^k,L 形毯子永远铺不满一个完整正方形)

在正中心放一块毯子,让它盖住另外三块各自「靠中心的那一格」:

        1    2    3    4
      +----+----+----+----+
   1  |    |    |    |    |     k = 2(4x4),公主 P 在 (2,2)
      +----+----+----+----+
   2  |    | P  |  a |    |     中心那 2x2 是 (2,2) (2,3) (3,2) (3,3)
      +----+----+----+----+     公主占了左上那格 -> 毯子盖住 a b c 三格
   3  |    | b  |  c |    |     拐角在 c = (3,3),缺口在左上 -> 输出「3 3 1」
      +----+----+----+----+
   4  |    |    |    |    |
      +----+----+----+----+

放完这一块之后,四个子块各有一个被占住的格子 —— 公主那块是公主,另外三块是刚铺的 a、b、c。 于是四块变成了四个一模一样的小问题,各自递归下去,边长为 1 时停。

★ 这一步就是「信任函数」那句话的完整版

solve(正方形, 已占住的那一格) —— 你只要保证每次递归下去的都是这个形状, 它自己会把整张图铺满。而「中心那块毯子」的全部作用,就是把三块没有缺口的正方形, 变成三块有缺口的正方形

★ 顺带算一下总块数:(4^k − 1) / 3k = 10 时是 349 525 块 —— 第 ⑦ 步会用到。

3★★ 真正卡住人的地方:c 到底怎么编号?

算法到上一步就写完了。可这道题还有一关和算法毫无关系,而且过不去就是零分编号

题面把形状定义在里。图我们存了一份(第 ⓪ 步那张),可图是给人看的,代码要的是另一句话

c 到底对应哪两格 —— 拐角在哪儿,另外两格往哪个方向伸?

从图翻到这句话,中间隔着一次「看图 → 写坐标」,而这一步特别容易译错

  • 图上标着 1 的那块,你读成「左上」还是「拐角在左上」?两种读法正好相反
  • 3 和 4 长得最像,顺手记反是一秒钟的事(第 ⑤ 步就是这么错的)。

⚠ 而且译错了自己发现不了:分治全对、格式全对、每行三个合法的数,交上去全错。

⇒ 与其盯着图确认,不如把它解出来原站那组样例本身就把编号锁死了。

✓ 不用猜 —— 样例把编号锁死了

原站给了一组样例(k = 3,公主在 (3,3),21 块毯子)。那 21 行就是一份标准答案, 把它按某种编号方案摆到 8×8 的棋盘上:

  • 猜对了 ⇒ 63 个格子恰好各盖一次,公主那格空着;
  • 猜错了 ⇒ 立刻出现重叠、出界或者漏格。

⇒ 24 种猜法逐个试一遍,能铺满的只有一种。这不是猜,是解出来的

p1228Derive.cpp把编号反推出来
不用输入,直接跑。24 行猜法里只有一行是「★ 铺满了」。
// P1228 —— 「毯子形状 1/2/3/4」到底怎么编号?拿样例把它反推出来
//
// 输入:无(原站那组样例写死在里面)
// 输出:24 种猜法逐个验一遍,最后剩下的那一种就是答案
//
// ★ 这份程序解决的是这道题**唯一真正的门槛**:
// 题面说毯子「只能有四种选择(如图)」—— 而那张图我们抄不过来(题面转录只有文字)。
// 编号猜错的话,算法一个字都没错,交上去照样全错。
//
// ★★ 但编号不用猜:**原站给了一组样例,样例本身就把编号锁死了。**
// 一块毯子占 2x2 里的三格,(x,y) 是拐角,另外两格必然是「上或下」+「左或右」。
// 于是 c=1..4 到底对应哪四种,一共只有 4! = 24 种可能 ——
// 把样例那 21 块按每种猜法摆到 8x8 的棋盘上,**能恰好铺满(公主那格除外)的只有一种**。
#include <bits/stdc++.h>
using namespace std;
// 原站样例:k = 3(8x8),公主在 (3,3),21 块毯子
const int SK = 3, SX = 3, SY = 3;
const int SAMPLE[21][3] = {
{5,5,1},{2,2,4},{1,1,4},{1,4,3},{4,1,2},{4,4,1},{2,7,3},
{1,5,4},{1,8,3},{3,6,3},{4,8,1},{7,2,2},{5,1,4},{6,3,2},
{8,1,2},{8,4,1},{7,7,1},{6,6,1},{5,8,3},{8,5,2},{8,8,1},
};
// 四种「另外两格往哪儿伸」:(dx, dy) —— dx = -1 上 / +1 下,dy = -1 左 / +1 右
const int DX[4] = {-1, -1, +1, +1};
const int DY[4] = {-1, +1, -1, +1};
const char* NAME[4] = {"上 + 左(缺口在左上)", "上 + 右(缺口在右上)",
"下 + 左(缺口在左下)", "下 + 右(缺口在右下)"};
int main() {
int n = 1 << SK;
int order[4] = {0, 1, 2, 3};
int okCount = 0, okOrder[4] = {0, 0, 0, 0};
int tried = 0;
do {
tried++;
vector<vector<int>> g(n + 2, vector<int>(n + 2, 0));
bool ok = true;
string why;
for (auto& p : SAMPLE) {
int x = p[0], y = p[1], c = p[2];
int d = order[c - 1]; // 这一种猜法里,c 对应哪个方向
int cell[3][2] = {{x, y}, {x + DX[d], y}, {x, y + DY[d]}};
for (auto& q : cell) {
int a = q[0], b = q[1];
if (a < 1 || a > n || b < 1 || b > n) { ok = false; why = "有格子出界"; break; }
if (a == SX && b == SY) { ok = false; why = "盖住了公主"; break; }
if (g[a][b]) { ok = false; why = "两块毯子重叠"; break; }
g[a][b] = 1;
}
if (!ok) break;
}
int covered = 0;
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) covered += g[i][j];
if (ok && covered != n * n - 1) { ok = false; why = "有格子没盖到"; }
printf("猜法 %2d:c=1->%d c=2->%d c=3->%d c=4->%d %s\n", tried,
order[0] + 1, order[1] + 1, order[2] + 1, order[3] + 1,
ok ? "★ 铺满了" : ("x " + why).c_str());
if (ok) { okCount++; for (int i = 0; i < 4; i++) okOrder[i] = order[i]; }
} while (next_permutation(order, order + 4));
printf("\n24 种猜法里,能把样例铺满的有 %d 种。\n", okCount);
if (okCount == 1) {
printf("⇒ 编号是唯一确定的,不用猜:\n\n");
for (int c = 1; c <= 4; c++) {
int d = okOrder[c - 1];
printf(" c = %d -> 另外两格是 (x%+d,y) 和 (x,y%+d) -> %s\n",
c, DX[d], DY[d], NAME[d]);
}
}
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果

跑出来的结论(下面整道题都按它写,而且它和原题图 1 完全一致 —— 区别是:现在这是验过的,不是看图看出来的):

24 种猜法里,能把样例铺满的有 1 种。
⇒ 编号是唯一确定的,不用猜:

   c = 1  ->  另外两格是 (x-1,y) 和 (x,y-1)  ->  上 + 左(缺口在左上)
   c = 2  ->  另外两格是 (x-1,y) 和 (x,y+1)  ->  上 + 右(缺口在右上)
   c = 3  ->  另外两格是 (x+1,y) 和 (x,y-1)  ->  下 + 左(缺口在左下)
   c = 4  ->  另外两格是 (x+1,y) 和 (x,y+1)  ->  下 + 右(缺口在右下)

★ 而它整理成一句话就是第 ① 步那句:c = 缺口在哪个角(1 左上、2 右上、3 左下、4 右下), 正好等于「公主/已占格落在哪个象限」 —— 于是代码里连转换都不用写。

★★ 这一步值得单独记一条

题面里「见图」的那部分,常常可以从样例反推出来 —— 而且往往是唯一解。

⚠ 反过来也要记住:只有一组样例的时候,这个反推能不能成立要自己验一遍 (这里是 24 选 1,样例那 21 块正好把四种形状全用上了,所以锁得死)。

4先造一把尺子:不交洛谷,也能判自己对不对

这道题是 special judge:合法方案有很多种,「和样例逐字节相同」这条尺子在这里是错的 (换一份合法答案照样满分)。能判的只有一件事:覆盖关系对不对。

⇒ 写一份自检程序:把答案还原成棋盘,逐格数它被盖了几次。 它报的四种错,和原站 spj 的四种报错一一对应:

p1228Check.cpp自检(把答案还原成棋盘)
这里喂给它的就是原站样例那 21 块(前两行是 k 和公主坐标)。
// P1228 自检:把一份答案还原成棋盘,看它到底合不合法
//
// 输入:第一行 k;第二行 x y(公主);接下来若干行 "x y c",读到文件尾
// 输出:一行结论。合法就报「n x n 的 N 格恰好各盖一次」,不合法就报是哪一种错
// (四种错和原站 spj 的报错代码一一对应:c 越界 / 坐标越界 / 重复覆盖 / 有格子没盖到)
//
// ★ 这份程序的意义:**这道题不用交到洛谷就能自己判对错。**
// 它是 special judge 题(方案不唯一),所以「和样例逐字节相同」这条尺子在这儿是错的 ——
// 换一份合法答案照样能过。能判的只有「覆盖关系对不对」。
#include <bits/stdc++.h>
using namespace std;
const int DX[5] = {0, -1, -1, +1, +1}; // c = 1..4:另外两格往哪儿伸
const int DY[5] = {0, -1, +1, -1, +1};
int main() {
int k, px, py;
if (scanf("%d %d %d", &k, &px, &py) != 3) { printf("读不到 k 和公主坐标\n"); return 0; }
int n = 1 << k;
vector<vector<int>> g(n + 2, vector<int>(n + 2, 0));
int x, y, c, pieces = 0;
while (scanf("%d %d %d", &x, &y, &c) == 3) {
pieces++;
if (c < 1 || c > 4) { printf("第 %d 块:c = %d 越界(spj 错误 1)\n", pieces, c); return 0; }
int cell[3][2] = {{x, y}, {x + DX[c], y}, {x, y + DY[c]}};
for (auto& q : cell) {
int a = q[0], b = q[1];
if (a < 1 || a > n || b < 1 || b > n) {
printf("第 %d 块:格子 (%d,%d) 越界(spj 错误 2)\n", pieces, a, b); return 0;
}
if (a == px && b == py) {
printf("第 %d 块:盖住了公主 (%d,%d)(spj 错误 3)\n", pieces, px, py); return 0;
}
if (g[a][b]) {
printf("第 %d 块:格子 (%d,%d) 被盖了两次(spj 错误 3)\n", pieces, a, b); return 0;
}
g[a][b] = 1;
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (!g[i][j] && !(i == px && j == py)) {
printf("格子 (%d,%d) 从没被盖过(spj 错误 4)\n", i, j); return 0;
}
printf("合法:%d x %d 的 %d 格恰好各盖一次,公主 (%d,%d) 没被盖,一共 %d 块毯子\n",
n, n, n * n - 1, px, py, pieces);
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果

5第 ① 版:分治一个字没错,编号猜成了「顺时针」

最容易顺手写出来的编号是顺时针:1 左上 → 2 右上 → 3 右下 → 4 左下。 看着比「先上下、再左右」自然多了 —— 它和正确答案只差把 3 和 4 换了个个儿

p1228Wrong.cpp第 ① 版(编号错)
和正解比一比:第 1 行都是「5 5 1」,从第 2 行开始就不一样了。
// 洛谷 P1228 —— 第 ① 版:分治一个字都没错,**编号是猜的**(所以全错)
//
// 输入:第一行 k(迷宫是 2^k x 2^k,0 < k <= 10);第二行 x y(公主所在的行、列)
// 输出:每行 "x y c" —— 一块毯子的拐角坐标,和它的形状编号
//
// 分治的形状(和 P5461 同源):
// 把正方形切成四块,公主在其中一块里;
// 在**正中心**放一块毯子,盖住另外三块各自靠中心的那一格 ——
// 于是那三块也「各有一个已经被占住的格子」,和公主那一块变成了同一个问题。
// ⇒ 四块各自递归,边长 1 时停。
//
// ★ 编号 c 不是猜的,是 p1228Derive.cpp 拿原站样例反推出来的(24 选 1,唯一):
// c = 1 缺口在左上 c = 2 缺口在右上 c = 3 缺口在左下 c = 4 缺口在右下
// 而「缺口」正好就是公主/已占格所在的那个象限 ⇒ **c 就是象限编号**,一行都不用记。
//
// ⚠ 输出量:k = 10 时是 (1024*1024 - 1) / 3 = 349525 行 ——
// 和 P5461 一样,这道题「打得快」和「算得快」都要管,所以关了同步、不用 endl。
#include <bits/stdc++.h>
using namespace std;
/**
* 铺满左上角为 (r,c)、边长 len 的正方形,其中 (hr,hc) 这一格已经被占住(公主或上一块毯子)。
*/
void solve(int r, int c, int len, int hr, int hc) {
if (len == 1) return;
int h = len / 2;
int mr = r + h - 1, mc = c + h - 1; // 中心那 2x2 的左上格
bool top = (hr <= mr), left = (hc <= mc); // 已占格落在哪个象限
// ⚠ 这一版把编号猜成了「顺时针」:1 左上、2 右上、3 右下、4 左下。
// 看着比「先上下、再左右」更自然 —— 而它把 3 和 4 换了个个儿。
int quad = top ? (left ? 1 : 2) : (left ? 4 : 3);
// 毯子的拐角 = 中心 2x2 里、和「已占格那个象限」对角的那一格
int cx = top ? mr + 1 : mr;
int cy = left ? mc + 1 : mc;
printf("%d %d %d\n", cx, cy, quad);
// 四个象限各自递归:已占格那一块用 (hr,hc),另外三块用刚被这块毯子盖住的那一格
solve(r, c, h, top && left ? hr : mr, top && left ? hc : mc);
solve(r, c + h, h, top && !left ? hr : mr, top && !left ? hc : mc + 1);
solve(r + h, c, h, !top && left ? hr : mr + 1, !top && left ? hc : mc);
solve(r + h, c + h, h, !top && !left? hr : mr + 1, !top && !left? hc : mc + 1);
}
int main() {
int k, x, y;
if (scanf("%d %d %d", &k, &x, &y) != 3) return 0;
solve(1, 1, 1 << k, x, y);
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果

把它的输出喂给上一步那把尺子,第 3 块就被判死:

第 3 块:格子 (2,1) 被盖了两次(spj 错误 3)
⚠ 这个错为什么值得单独写一版

它有三个特点,凑在一起就是「最难查」的那一类:

  1. 算法完全正确 —— 分治、递归、边界一个字都不用改;
  2. 自己看输出看不出来 —— 每行都是三个合法的数,格式挑不出毛病;
  3. 样例也未必挡得住 —— 第一行还是对的;而 k = 1 且公主在第一行时(1 1 / 1 2),错版和正解逐字节相同(实测,两条都写成断言了)。

⇒ 唯一能救你的,就是第 ④ 步那把尺子:写一份把答案还原回棋盘的自检程序。 输出是「方案」而不是「一个数」的题,都该这么干。

6第 ② 版:正解(编号照反推来的那份)

p1228.cpp第 ② 版(正解)
和原题样例逐字节相同。试试把公主挪到 1 1,或者把 k 调到 10(349525 行)。
// 洛谷 P1228 地毯填补问题 —— 正解:分治,每次在中心放一块毯子
//
// 输入:第一行 k(迷宫是 2^k x 2^k,0 < k <= 10);第二行 x y(公主所在的行、列)
// 输出:每行 "x y c" —— 一块毯子的拐角坐标,和它的形状编号
//
// 分治的形状(和 P5461 同源):
// 把正方形切成四块,公主在其中一块里;
// 在**正中心**放一块毯子,盖住另外三块各自靠中心的那一格 ——
// 于是那三块也「各有一个已经被占住的格子」,和公主那一块变成了同一个问题。
// ⇒ 四块各自递归,边长 1 时停。
//
// ★ 编号 c 不是猜的,是 p1228Derive.cpp 拿原站样例反推出来的(24 选 1,唯一):
// c = 1 缺口在左上 c = 2 缺口在右上 c = 3 缺口在左下 c = 4 缺口在右下
// 而「缺口」正好就是公主/已占格所在的那个象限 ⇒ **c 就是象限编号**,一行都不用记。
//
// ⚠ 输出量:k = 10 时是 (1024*1024 - 1) / 3 = 349525 行 ——
// 和 P5461 一样,这道题「打得快」和「算得快」都要管,所以关了同步、不用 endl。
#include <bits/stdc++.h>
using namespace std;
/**
* 铺满左上角为 (r,c)、边长 len 的正方形,其中 (hr,hc) 这一格已经被占住(公主或上一块毯子)。
*/
void solve(int r, int c, int len, int hr, int hc) {
if (len == 1) return;
int h = len / 2;
int mr = r + h - 1, mc = c + h - 1; // 中心那 2x2 的左上格
bool top = (hr <= mr), left = (hc <= mc); // 已占格落在哪个象限
int quad = (top ? 0 : 2) + (left ? 0 : 1) + 1; // 1 左上 2 右上 3 左下 4 右下
// 毯子的拐角 = 中心 2x2 里、和「已占格那个象限」对角的那一格
int cx = top ? mr + 1 : mr;
int cy = left ? mc + 1 : mc;
printf("%d %d %d\n", cx, cy, quad);
// 四个象限各自递归:已占格那一块用 (hr,hc),另外三块用刚被这块毯子盖住的那一格
solve(r, c, h, top && left ? hr : mr, top && left ? hc : mc);
solve(r, c + h, h, top && !left ? hr : mr, top && !left ? hc : mc + 1);
solve(r + h, c, h, !top && left ? hr : mr + 1, !top && left ? hc : mc);
solve(r + h, c + h, h, !top && !left? hr : mr + 1, !top && !left? hc : mc + 1);
}
int main() {
int k, x, y;
if (scanf("%d %d %d", &k, &x, &y) != 3) return 0;
solve(1, 1, 1 << k, x, y);
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果

三条值得看的证据:

① k = 3、公主 (3,3)  ->  和原站样例逐字节相同     (编号反推对了)
② k = 1..10 的每一组  ->  自检程序全部报「合法」   (算法对了)
③ k = 10             ->  349525 行,1048575 格恰好各盖一次
★ 「和样例逐字节相同」在 spj 题里是彩蛋,不是标准

这道题的正解不必和样例一致 —— 我们这份正好一致,是因为递归的顺序碰巧和出题人一样。

⇒ 所以别把它当验收标准:验收标准是第 ④ 步那把尺子(覆盖关系), 而「碰巧和样例一样」只是一条额外的旁证。

7还剩最后一关:349525 行的输出

k = 10 时要打 349 525 行。和 P5461 是同一课:

「算得快」和「打得快」是两件事。

这一版用的是 printf;换成 cout << ... << endl 的话,endl 每行都强制刷一次缓冲, 输出量大的时候能单独把你卡掉。

⇒ 两条写法二选一,别混:printf,或者 coutios::sync_with_stdio(false) 且不用 endl

8回头看:这道题在教什么

✓ 三件带得走的东西
  1. ★★ 题面里「见图」的部分,常常能从样例反推出来。 这道题的四个编号是 24 选 1, 而样例把它锁死了 —— 不确定的东西,先想想有没有办法把它解出来,再考虑猜。
  2. 输出是「方案」的题,第一件事是写自检程序。 方案题多半是 spj, 「和样例比」这条尺子失效;能判的只有覆盖 / 合法性,而那个程序通常十几行。
  3. 分治的关键是「把不能递归的变成能递归的」。 中心那一块毯子什么都没算, 它只干一件事:给另外三块各制造一个缺口。