完全图边权只有 p/q,两点最短路只需比较直达和一次中转。
P14079 [GESP202509 八级] 最短距离
GESP8 冲刺课堂页:先建模,再压缩状态,最后读代码。
一、先回答问题
看到 N=10^18 就想建图或跑最短路,实际只能做数学分类。
二、核心观察
两点互质时直达是 p,不互质时直达是 q;巨大点集保证合适中间点存在。
为什么不丢答案:p、q 都为正,超过两条边不会优于某个直达或两段中转方案。
gcd(a,b)
直达
一次中转
三、互动演示
步骤1
关键状态 A-
关键状态 B-
答案/目标-
复杂度看表
课堂动作手推
点击下一步开始。
四、自己选答案
为什么不用三条边?
先判断,再点按钮。
a 或 b 为 1 时为什么特判?
先判断,再点按钮。
五、手推结果
| 情况 | 直达 | 可选绕路 | 答案 |
|---|---|---|---|
| a=b | 0 | - | 0 |
| gcd=1 | p | 2q | min(p,2q) |
| gcd>1 | q | 2p | min(q,2p) |
课堂要求:每题先说清对象、关系、保留的信息、压缩掉的信息,再写代码。
六、C++14 参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
ll p, q;
if (!(cin >> n >> p >> q)) return 0;
while (n--) {
ll a, b;
cin >> a >> b;
if (a == b) {
cout << 0 << "\n";
} else if (a == 1 || b == 1) {
cout << p << "\n";
} else {
ll g = __gcd(a, b);
if (g == 1) {
// 互质:直达为 p,或者绕路找不互质的点为 2q
cout << min(p, 2 * q) << "\n";
} else {
// 不互质:直达为 q,或者绕路找互质的点为 2p
cout << min(q, 2 * p) << "\n";
}
}
}
return 0;
}