题解 P1458 【顺序的分数 Ordered Fractions】
发现很多题解都是枚举+sort做的……
这里介绍一种方法:分治。
我们假设有两个分数a/b<c/d。我们要从小到大输出这个区间上满足题意的分数。
我们令m = a + c, n = b + d。可证明a / b < m / n < c / d. (交叉相乘即可证明)
并且我们可以证明这些分数都是最简的。(并不会证明233)
那么我们只需要对m/n的左右两个区间继续分治,即可按顺序得到所求分数。
然后这种方法来源于做过的一道 分数树 的题。这里贴个链接:http://www.docin.com/p-1022648660.html
(2019.7.11 upd) 对以上部分内容进行补充:
可以发现这样分治过程形成了一棵树,这样的树叫做 Stern-Brocot Tree。这棵树能够不重不漏的表示所有有理数(既约分数)。
构造方法是:第一层是
则有如下性质:对于任意构造阶段的两个相邻分数
接着由这个性质可以证明每个有理数都存在:假设
于是:
又由
而右边可以取到
接着可以发现树中每个有理数是不重复的,因为
这道题只需要从
然后上代码(Pas代码下面几篇题解里有,这里贴C++的)
#include <iostream>
#include <cstdio>
using namespace std;
int N;
void DFS(const int& l1, const int& l2, const int& r1, const int& r2)
{
if(l2 > N || r2 > N)
return;
DFS(l1, l2, l1 + r1, l2 + r2);
if(l2 + r2 <= N)
printf("%d/%d\n", l1 + r1, l2 + r2);
DFS(l1 + r1, l2 + r2, r1, r2);
}
int main()
{
cin >> N;
printf("0/1\n");
DFS(0, 1, 1, 1);
printf("1/1\n");
return 0;
}