题单 · 习题解析

洛谷 P1547 [USACO05MAR] Out of Hay S

★★ 升序收边 ⇒ 答案就是 Kruskal **最后收下的那一条**,一个赋值就完;★★★ 「MST 的最长边」≡「所有生成树里最长边的最小值」(枚举所有生成树 **300 / 300**,顺带证了「所有 MST 的最长边一样」);★★★ 一条草稿被打回:`max` 写在 `continue` 前面**是对的** —— **是那句 `break` 在兜底**,⚠ 而这个「精确的 0」配了自检(去掉 break 当场 268 / 300);★★ 题面明说的**重边**,对 Kruskal 是**噪声**、对**邻接矩阵 + Prim 是命门**(触发 300 / 真被抓 129);★★ 「保证连通」同样两个写法分量不同 —— Prim 会把 `0x3f3f3f3f` 当答案打出来(300 / 300);⚠ **这道题有两份题面**:USACO 原版要两个数、洛谷这份要一个 ⇒ 照抄题解会多打一个数;★ 「**总长度** ≤ 10⁹」⇒ 连权和都撑不破 int(余量 2.1 倍)

原题:洛谷 P1547出自 第 34 章 最小生成树:Kruskal 与 Prim 的题单题面本地存档:2026-08-31
⚠ 先自己写一遍,再往下看

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

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

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

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

转录自洛谷 P1547,日期见页头。两边不一致时信原站。 ⚠ 这道题尤其要看清这一份 —— 它和 USACO 的原版输出格式不一样,见本页第 ⑤ 步。

题目描述

Bessie 计划调查 N2 ≤ N ≤ 2000)个农场的干草情况,它从 1 号农场出发。农场之间总共有 M1 ≤ M ≤ 10⁴)条双向道路,所有道路的总长度不超过 10⁹有些农场之间存在着多条道路所有的农场之间都是连通的

Bessie 希望计算出该图中最小生成树中的最长边的长度。

输入格式

第一行两个整数 N, M

接下来 M 行,每行三个用空格隔开的整数 Aᵢ, Bᵢ, Lᵢ,表示 Aᵢ, Bᵢ 之间有一条道路,长度为 Lᵢ

输出格式

一个整数,表示最小生成树中的最长边的长度。

说明/提示

时限 1 秒,内存 125 MB。

输入输出样例

输入

3 3
1 2 23
2 3 1000
1 3 43

输出

43

三条路 23 / 1000 / 43。最小生成树选 1-2(23)和 1-3(43), 最长的那条是 43 —— 那条 1000 的路根本用不上。

1★ 关键的一步:答案就是 Kruskal 收下的最后一条边

★★ 升序收边 ⇒ 「最后收下的」就是「最长的」

Kruskal 是按权升序扫边的。它收下的那 n − 1 条边,权值也是升序的 ⇒ 最小生成树里最长的那条,就是它收下的最后一条。

max 都不用取 —— 一个赋值就完了:

ans = t[0];      // 每收一条就覆盖一次,循环结束时它就是最后那条
p1547.cpp★ 这一版就能 AC(顶格 n = 2000 / m = 10⁴,本机 4 毫秒)
// P1547 [USACO05MAR] Out of Hay S —— ★ 这一版就能 AC
//
// ★ 关键的一步只有半行:Kruskal 是**按权升序**收边的
// ⇒ 「最小生成树里最长的那条」就是**它收下的最后一条**。
// 连 max 都不用取(取了也没错,见 p1547All.cpp 那个位置写错的反面教材)。
//
// ⚠ 题面明写着两句保证,各值一件事:
// ①「所有的农场之间都是连通的」⇒ **不用判无解**(对照 [P3366](/sol/p3366/) 的 orz);
// ②「所有道路的总长度不超过 10⁹」—— ★ 这句的主语是**总和**,
// 于是连「权和」都撑不破 int,更别说单条边 ⇒ **不用 long long**。
// ⚠ 另外题面明说「有些农场之间存在着多条道路」—— 重边。Kruskal 天然不怕,
// 而换成邻接矩阵存图就得当心(见 p1547Mat.cpp)。
#include <bits/stdc++.h>
using namespace std;
int fa[2005];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 3>> e(m);
for (auto& t : e) cin >> t[1] >> t[2] >> t[0]; // 读进来是 A B L,存成 (L, A, B)
sort(e.begin(), e.end());
for (int i = 1; i <= n; i++) fa[i] = i;
int ans = 0, cnt = 0;
for (auto& t : e) {
int x = find(t[1]), y = find(t[2]);
if (x == y) continue; // ⚠ 跳过的边**不算数**,位置很要紧
fa[x] = y;
ans = t[0]; // ★ 升序收边 ⇒ 最后收下的就是最长的
if (++cnt == n - 1) break;
}
cout << ans << '\n';
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
★★★ 「为什么它一定是所有生成树里最小的最长边」—— 走一条完全无关的路验一遍

题面问的是「最小生成树里的最长边」,而这道题真正的用处是瓶颈生成树: 在所有生成树里,最长边最小的那棵。这两句话是不是一回事?

写一份和 Kruskal 一行不共享的参照物:枚举所有生成树,各算各的最长边,取最小 ——

300 组
「最小生成树的最长边」≡「所有生成树里最长边的最小值」 300 / 300
所有权和最小的生成树,最长边都一样 300 / 300

★ 第二行是白送的推论也是必要的一步 —— 否则「最小生成树的最长边」这句话本身就没定义。 (背后是那条标准结论:所有最小生成树的边权多重集完全相同。)

⇒ 又一次「验算走一条和算法完全无关的路」

2⚠ 最容易的一发 WA:打出了权和

p1547Sum.cpp✗ 打出了最小生成树的权和(样例打出 66,当场挡住)
// ✗ P1547:打出了最小生成树的**权和**
//
// 这道题挂在第 34 章的题单里,前面几道又全是「求权和」——
// 于是写完 Kruskal 顺手 `cout << sum` 是最自然不过的一发 WA。
// ★ 它是「每组都错」型(除非那棵树只有一条边),官方样例当场挡住(66 vs 43)。
#include <bits/stdc++.h>
using namespace std;
int fa[2005];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 3>> e(m);
for (auto& t : e) cin >> t[1] >> t[2] >> t[0];
sort(e.begin(), e.end());
for (int i = 1; i <= n; i++) fa[i] = i;
long long sum = 0;
int cnt = 0;
for (auto& t : e) {
int x = find(t[1]), y = find(t[2]);
if (x == y) continue;
fa[x] = y;
sum += t[0]; // ✗ 题目问的是最长的那一条,不是和
if (++cnt == n - 1) break;
}
cout << sum << '\n';
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果

这道题挂在第 34 章的题单里,前面几道又全是「求权和」—— 写完 Kruskal 顺手 cout << sum 是最自然不过的一发 WA。四个档全是 300 / 300,官方样例一测就死。

3★★★ 一个被实测打回来的草稿:max 写在 continue 前面,居然是对的

p1547All.cpp⚠ 看着像 bug —— 1200 轮被抓 0 次
// ⚠⚠ P1547:取 max 那一行写在了 `continue` 前面 —— 而它**一次都没错**
//
// 草稿里把这一版当成错法收了进来,理由听着很顺:「被判环跳过的边也被算进 max 了,
// 那不就成了**全图**最长的边?」——**四个档 1200 轮,被抓 0 次。**
//
// ★★★ 一行就能证明它为什么对:
// 边是**升序**扫的,而 Kruskal 收够 `n − 1` 条就 `break`
// ⇒ **被扫到的每一条边,都不比最后收下的那一条长。**
// 于是 `max` 取到的就是最后收下的那条 —— 和正解一模一样。
//
// ⚠ 而这个「精确的 0」**配了自检才敢写**:把那句 `break` 去掉,它当场就错
// (见 p1547NoBreak.cpp,档 0 抓 **203 / 300**)。
// ⇒ 「[一个反例都没有](/sol/p1439/)」和「这段代码根本没在跑」输出一模一样。
//
// ⇒ ★★ 真正的结论不是「max 写哪儿都行」,是**「那句 break 在替它兜底」** ——
// 两处细节各自都不起眼,凑在一起才让它是对的。
#include <bits/stdc++.h>
using namespace std;
int fa[2005];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 3>> e(m);
for (auto& t : e) cin >> t[1] >> t[2] >> t[0];
sort(e.begin(), e.end());
for (int i = 1; i <= n; i++) fa[i] = i;
int ans = 0, cnt = 0;
for (auto& t : e) {
ans = max(ans, t[0]); // ✗ 跳过的边也被算进来了
int x = find(t[1]), y = find(t[2]);
if (x == y) continue;
fa[x] = y;
if (++cnt == n - 1) break;
}
cout << ans << '\n';
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
★★★ 它为什么对:那句 break 在替它兜底

草稿里把这一版当成错法收了进来,理由听着很顺: 「被判环跳过的边也被算进 max 了,那不就成了全图最长的边?」

四个档 1200 轮,被抓 0 次。 一行就能证明:

边是升序扫的,而 Kruskal 收够 n − 1 条就 break被扫到的每一条边,都不比最后收下的那一条长。

于是 max 取到的恰好就是最后收下的那条 —— 和正解一模一样。

⇒ ★★ 真正的结论不是「max 写哪儿都行」,而是 那句 break 在替它兜底 —— 两处细节各自都不起眼,凑在一起才让它是对的。

⚠ 而这个「精确的 0」配了自检才敢写 —— 把 break 去掉,它当场就错

「一个反例都没有」和「这段代码根本没在跑」输出一模一样。 所以这一页专门留了一份已知错的东西:同样的 max 位置,但没有那句 break

p1547NoBreak.cpp✗ 自检用:去掉 break 之后它算的是全图最长边(样例打出 1000)
// ✗ P1547(自检用):取 max 写在 `continue` 前面,**而且没有那句 break**
//
// ★★ 它的存在只有一个目的:证明「p1547All.cpp 被抓 0 次」不是因为对拍没在跑。
// 两处细节各自都不起眼,凑在一起才让 p1547All 是对的 ——
// 把 `break` 去掉,「跳过的边也算进 max」立刻变成一个实打实的 bug:
// 它算的是**全图最长的那条边**。
//
// ⇒ [「报『精确的 0』之前,先拿一个已知错的东西验证这段代码是活的」](/sol/p1094/)
// —— 这一份就是那个「已知错的东西」。
#include <bits/stdc++.h>
using namespace std;
int fa[2005];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 3>> e(m);
for (auto& t : e) cin >> t[1] >> t[2] >> t[0];
sort(e.begin(), e.end());
for (int i = 1; i <= n; i++) fa[i] = i;
int ans = 0;
for (auto& t : e) {
ans = max(ans, t[0]); // ✗ 跳过的边也算进来
int x = find(t[1]), y = find(t[2]);
if (x == y) continue;
fa[x] = y; // ✗ 而且没有 break —— 一路扫到底
}
cout << ans << '\n';
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
300 轮 档 0 档 1 重边 ★ 档 2 输入本身是一棵树 档 3 大量并列
max 位置写错 + 保留 break 0 0 0 0
max 位置写错 + 去掉 break 268 298 0 148

★★ 对拍代码是活的(268 / 298 / 148),⇒ 上面那一行的 0 是真的。 ★ 而档 2 那个 0 也是能证的:输入本身就是一棵树 ⇒ 一条边都不会被跳过,两版必然相同。 ⇒ 一张表里同时有「能证的 0」和「代码是活的」,这一档两件事一起干完了。

4★★ 重边:题面自己提醒了,而它只在一种存法上咬人

p1547Mat.cpp✗ 邻接矩阵 + 朴素 Prim,重边直接赋值(样例照过)
// ✗ P1547:邻接矩阵 + 朴素 Prim,重边直接赋值不取 min
//
// `n ≤ 2000` ⇒ 矩阵 2001 × 2001 × 4 ≈ **16 MB**(题面给 125 MB),**放得下**,
// 而 `O(n²) = 4 × 10⁶` 也够快 ⇒ 朴素 Prim 在这道题上是一条**真能走通**的路。
//
// ★★ 可它比 Kruskal 多背了一个包袱:**题面明写着「有些农场之间存在着多条道路」。**
// 矩阵一个格子只放得下一条边,顺手写 `g[a][b] = l` 的话,
// **后读进来的那条会把先读进来的短边盖掉**。
// ⇒ 这是 [B3647 那个坑](/sol/b3647/) 在 MST 上的复现,而这次**题面自己提醒过你了**。
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
static int g[2005][2005];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
memset(g, 0x3f, sizeof g);
for (int i = 0; i < m; i++) {
int a, b, l;
cin >> a >> b >> l;
g[a][b] = g[b][a] = l; // ✗ 没有 min —— 重边把短的盖掉了
}
vector<char> in(n + 1, 0);
vector<int> best(n + 1, INF);
best[1] = 0;
int ans = 0;
for (int it = 0; it < n; it++) {
int u = -1;
for (int i = 1; i <= n; i++)
if (!in[i] && (u < 0 || best[i] < best[u])) u = i;
in[u] = 1;
ans = max(ans, best[u]);
for (int i = 1; i <= n; i++)
if (!in[i] && g[u][i] < best[i]) best[i] = g[u][i];
}
cout << ans << '\n';
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
★★ 同一句「有些农场之间存在着多条道路」,对两个写法分量完全不同

n ≤ 2000 ⇒ 矩阵 2001 × 2001 × 415 MB(题面给 125 MB), O(n²) = 4 × 10⁶ 也够快 ⇒ 朴素 Prim 在这道题上是一条真能走通的路

可它比 Kruskal 多背一个包袱:矩阵一个格子只放得下一条边。

那句「有多条道路」 Kruskal 邻接矩阵 + Prim
分量 噪声find 天然把重边判成环) ★★ 命门(少半行 min 就错)
档 1(重边档)· 300 轮
输入里真的有重边 300
被盖掉的短边真的改变了答案 129
⇒ 「不取 min」被抓 129

★ 触发条件 300、真被抓 129 ⇒ 两层,差 2.3 倍 —— 第一层写得太粗(有重边 ≠ 它影响答案)。 ⚠ 而顺手写的生成器在「互不相同的点对」里挑边,结构上造不出重边 ⇒ 另外三档全是精确的 0。

★★ 「这句约束重不重要,是『题目 × 你写的那一版』的属性」—— 这条本书已经量到第五、六次了

p1547Prim.cpp★ 同一份写法加上半行 min —— 它就能 AC 了
// ★ P1547 的另一条路:朴素 Prim(矩阵存图,**重边取 min**)—— 它也能 AC
//
// 和上面那份 p1547Mat.cpp 只差 `min(...)` 那半行 ——
// ★ 这一对是本页最干净的对照:**同一个写法,加不加那半行就是正解和错法。**
// 矩阵 2001 × 2001 × 4 ≈ 16 MB,`O(n²) = 4 × 10⁶`,顶格本机见本页第 ⑥ 步那张表。
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
static int g[2005][2005];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
memset(g, 0x3f, sizeof g);
for (int i = 0; i < m; i++) {
int a, b, l;
cin >> a >> b >> l;
g[a][b] = g[b][a] = min(g[a][b], l); // ★ 就是这半行
}
vector<char> in(n + 1, 0);
vector<int> best(n + 1, INF);
best[1] = 0;
int ans = 0;
for (int it = 0; it < n; it++) {
int u = -1;
for (int i = 1; i <= n; i++)
if (!in[i] && (u < 0 || best[i] < best[u])) u = i;
in[u] = 1;
ans = max(ans, best[u]);
for (int i = 1; i <= n; i++)
if (!in[i] && g[u][i] < best[i]) best[i] = g[u][i];
}
cout << ans << '\n';
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
★ 这一对是本页最干净的对照:同一个写法,加不加那半行就是正解和错法
A 机 · WSL2 · 8 核 / 7 G · 2026-08-31 · 独占 · 顶格 n = 2000 / m = 10⁴(输入 146 756 字节)· 5 次取最小
Kruskal 4 毫秒
朴素 Prim(矩阵 15 MB,含 memset 19 毫秒

⇒ 两条路都过得轻松,选 Kruskal 的理由不是快,是「它不用为重边操心」

5⚠ 和算法完全无关的一条:这道题有两份不同的题面

p1547Two.cpp✗ 按 USACO 原版输出两个数(样例打出「43 1」,挡住了)
// ✗ P1547:按 USACO 原版的格式,输出了**两个**数
//
// ★ 这个坑不在算法里,在「你照着哪一份题面写」上:
// USACO 原题要的是「最长边 + 有多少条边的长度等于它」,
// 而本地存的这份洛谷题面(见页头「题目原文」)写得很清楚:
// 输出格式是「**一个整数**」,样例输出也只有一个 `43`。
// ⇒ 网上不少题解是照原版写的,**照抄会多打一个数**。
// ⚠ 两边不一致时信原站 —— 这也正是每个解析页都要把题面存一份的理由。
#include <bits/stdc++.h>
using namespace std;
int fa[2005];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<array<int, 3>> e(m);
for (auto& t : e) cin >> t[1] >> t[2] >> t[0];
sort(e.begin(), e.end());
for (int i = 1; i <= n; i++) fa[i] = i;
int ans = 0, cnt = 0;
for (auto& t : e) {
int x = find(t[1]), y = find(t[2]);
if (x == y) continue;
fa[x] = y;
ans = t[0];
if (++cnt == n - 1) break;
}
int same = 0;
for (auto& t : e) if (t[0] == ans) same++;
cout << ans << ' ' << same << '\n'; // ✗ 这一行多出来的那个数
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
★ 这正是「题面必须在本地存一份」要防的那件事

USACO 的原题要的是两个数(最长边 + 有多少条边的长度等于它), 而本地存的这份洛谷题面(见第 ⓪ 步)写得很清楚:

输出格式:一个整数,表示最小生成树中的最长边的长度。

样例输出也只有一个 43。⇒ 网上不少题解是照原版写的,照抄会多打一个数。

★ 这一条对拍逐字节比抓得到(四档全是 300 / 300),但它和算法一个字的关系都没有 —— 和 P3366 那个 Orz 是同一类:唯一的防线是把题面看完,并且看的是正确的那一份。 ⚠ 而这也是每个解析页都要转录题面的理由:两边不一致时信原站, 但至少你手里有一份写着日期的存档,知道自己当时照的是哪一份。

6★ 题面那两句保证,各值一件事

★ 「所有道路的总长度不超过 10⁹」—— 这句话的主语是总和
题面保证的总长度 10⁹
int 上限 2 147 483 647 ⇒ 余量 ★ 2.1 倍

⇒ 于是连「所有道路的权和」都撑不破 int单条边更不可能 ⇒ 不用 long long

★ 这是「答案 ≥ 任何一个被用到的中间值」那条论证模式的反向用法: 那些页是从答案往上界推,这道题是题面直接把总和的上界给了你。 ⚠ 而余量只有 2.1 倍 —— 要是题面写的是「不超过 10¹⁰」,结论就翻过来了。

★★ 「所有的农场之间都是连通的」—— 同一句保证,两个写法分量又不同

造一档违反它的数据(点分两块)跑 300 组:

Kruskal 版 朴素 Prim 版
结论 照样给出「最小生成森林」的最长边 打出 1061109567
两版分家 300 / 300

那个 1061109567 就是 0x3f3f3f3f —— Prim 从 1 号点长,够不着的点 best 一直是 INF, 而 max 把它收了下来。

⇒ ★★ 这一页第二次量到「同一句约束,两个写法分量不同」(上一次是重边)—— 而这一次连方向都反了:重边那次是 Prim 更脆,连通性这次还是 Prim 更脆。 ⇒ 选 Kruskal 的理由到这儿凑齐了两条,都不是「快」

7★ 对拍这一页

参照物是枚举所有生成树:找出权和最小的那棵,取它的最长边。

p1547Brute.cpp参照物:枚举所有生成树(300 轮不一致 0 轮)
300 轮(n 随机 4~6) 档 0 默认 ★★ 档 1 重边 ★ 档 2 输入是树 ★ 档 3 大量并列
Kruskal(正解) 0 0 0 0
朴素 Prim(取 min) 0 0 0 0
打出权和 300 300 300 300
max 位置写错(有 break) 0 0 0 0
max 位置写错(无 break) 268 298 0 148
输出两个数 300 300 300 300
矩阵存图不取 min 0 129 0 0
★★★ 兑现本章第 10 步:两棵树可能不一样,那对拍该比什么
300 组 档 0 ★ 档 3 大量并列
Kruskal 和 Prim 选的边不同 7 72
两版最长边不同 0 0

⇒ 和 P1546(6 / 39)、P2820(8 / 74)连成第三个点: 并列一多,两个都正确的写法就会分岔,而题目要的那个量从来没变过。 ★ 这一章三道题各量了一遍,结论一次没变 ⇒ 比题目要的那个数,别比边集。

★ 官方样例这一轮挡住了三个里的三个 —— 而漏掉的那个是「每组都错」型
错法 抓获率(最狠的那一档) 官方样例挡住了吗
打出权和 300 / 300 挡住了(打出 66)
max 写错 + 无 break 298 / 300 挡住了(打出 1000)
输出两个数 300 / 300 挡住了(打出「43 1」)
矩阵存图不取 min 129 / 300 放过了 —— 样例三条边、没有重边

⇒ 又一次:放过的那个不是因为它罕见(在它的档上 129 / 300 不算低), 是因为那三行 1 2 23 / 2 3 1000 / 1 3 43 结构上问不出这个问题P1746 那条)。

8度量程序和生成器

p1547Count.cpp度量程序(本页所有数字都出自它)
p1547Gen.cpp(五个档位)数据生成器

9一页纸

★★ 关键的一步 升序收边 ⇒ 答案就是最后收下的那一条,一个赋值就完
★★★ 走一条无关的路验 「MST 的最长边」≡「所有生成树里最长边的最小值」300 / 300
★★★ 草稿被打回 max 写在 continue 前面是对的 —— ★ 是那句 break 在兜底
⚠ 而那个 0 配了自检 去掉 break 当场 268 / 300 ⇒ 「代码是活的」和「能证的 0」同一张表
★★ 重边 题面明说了 —— 对 Kruskal 是噪声,对邻接矩阵 + Prim 是命门(300 触发 / 129 被抓)
★★ 保证连通 同样两个写法分量不同:Prim 会把 0x3f3f3f3f 当答案打出来(300 / 300)
⚠ 两份题面 USACO 原版要两个数、洛谷这份要一个 ⇒ 照抄题解会多打一个数
★ 算术 总长度 ≤ 10⁹」⇒ 连权和都撑不破 int(余量 2.1 倍);矩阵 15 MB / 125 MB