🧠 题目描述(洛谷 P1014)
Georg Cantor 用一张 Z 字形编号的表,展示了有理数的可枚举性。如下:
1/1
1/2 2/1
3/1 2/2 1/3
1/4 2/3 3/2 4/1
...
第 N 项是第几对分数?输入 N(1 ≤ N ≤ 10^7),输出对应的 “a/b”。
👉 洛谷题目链接↗
💡 解题思路
我们可以观察到,Z 字形编号的表是按照“对角线编号”来填充的。
- 第 1 条对角线有 1 项 → 和为 2
- 第 2 条对角线有 2 项 → 和为 3
- 第 3 条对角线有 3 项 → 和为 4 …
因此,第 N 项一定处于某一条对角线 n
上,满足:
n(n+1)/2 ≥ N
我们可以从 n=1 开始枚举,直到找到这个对角线为止。
#include <iostream>
using namespace std;
int main() {
int t;
cin >> t;
// 🌟 用 while 找到所在的对角线编号
int n = 1;
while (n * (n + 1) / 2 < t) n++;
int offset = t - (n - 1) * n / 2;
if (n % 2 == 0)
cout << offset << "/" << (n + 1 - offset);
else
cout << (n + 1 - offset) << "/" << offset;
return 0;
}
有没有更优解法?
这个 while
枚举的方式相比开方取整,更清晰更鲁棒。
有没有犯错? 一开始我用 sqrt(2*t)
来估算对角线位置,但处理边界比较麻烦。 这个 while 写法更稳定。
Thanks for reading!