欧拉计划 Project Euler 71(有序分数)题解
欧拉计划 Project Euler 71 题解
- 题干
- 有序分数
- 思路
- 为什么可以这样 理论依据
- code
题干
有序分数
考虑形如 n d \frac{n}{d} dn的分数,其中 n n n和 d d d均为正整数。如果 n < d n<d n<d且其最大公约数为1,则称该分数为最简真分数。
将所有 d ≤ 8 d\leq8 d≤8的最简真分数构成的集合按大小升序排列:
1 8 , 1 7 , 1 6 , 1 5 , 1 4 , 2 7 , 1 3 , 3 8 , 2 5 , 3 7 , 1 2 , 4 7 , 3 5 , 5 8 , 2 3 , 5 7 , 3 4 , 4 5 , 5 6 , 6 7 , 7 8 \frac 1 8, \frac 1 7, \frac 1 6, \frac 1 5, \frac 1 4, \frac 2 7, \frac 1 3, \frac 3 8, \mathbf{\frac 2 5}, \frac 3 7, \frac 1 2, \frac 4 7, \frac 3 5, \frac 5 8, \frac 2 3, \frac 5 7, \frac 3 4, \frac 4 5, \frac 5 6, \frac 6 7, \frac 7 8 81,71,61,51,41,72,31,83,52,73,21,74,53,85,32,75,43,54,65,76,87
可以看出 2 5 \frac{2}{5} 52是 3 / 7 3/7 3/7直接左邻的分数。
将所有的 d ≤ 1000000 d\leq1000000 d≤1000000的最简真分数按大小升序排列,求此时 3 7 \frac{3}{7} 73直接左邻的分数的分子。
思路
很显然这是不能暴力构造的,因为数据太过庞大了。
我们可以枚举所有的 d ≤ 1000000 d\leq1000000 d≤1000000,对于每个 d d d,令 d = f l o o r ( 3 ∗ d − 1 ) / 7 d=floor(3 * d-1)/7 d=floor(3∗d−1)/7,这样是为了确保 n d < 3 7 \frac{n}{d} < \frac{3}{7} dn<73,然后检查 n n n和 d d d是否互质,维护目前最大的 n d \frac{n}{d} dn即可
为什么可以这样 理论依据
对于每个分母 q q q,我们只需要考虑一个分子 p p p,即:
p = ⌊ a ⋅ q − 1 b ⌋ p=\lfloor\frac{a\cdot q-1}{b}\rfloor p=⌊ba⋅q−1⌋
这是保证 p q < a b \frac{p}{q} < \frac{a}{b} qp<ba最大的那个 p q \frac{p}{q} qp
为了进一步加速,我们可以从大到小便利分母,并尽早结束循环
定义:
δ = a ⋅ q − b ⋅ p \delta = a\cdot q - b\cdot p δ=a⋅q−b⋅p
若找到某个分数满足 δ = 1 \delta=1 δ=1那么这个分数已经是距离 a b \frac{a}{b} ba最近的最简真分数,可立即停止,这里有理论依据支撑的
code
// --->428570 999997
#include <bits/stdc++.h>using namespace std;using ll = long long;// 这段 lambda 内部的代码会在 main() 调用之前被执行。
int __OI_INIT__ = []() {ios::sync_with_stdio(0), cin.tie(0);cout.tie(0);cout << fixed << setprecision(12); // 设置输出浮点数默认精度为 12 位。return 0;
}();// 用法
/*int a = 1;double k = 2.0;string s = "hello world";_(a, k, s);输出 --->1 2.000000000000 hello world
*/
template<class... Args> void _(Args... args) {auto _ = [&](auto x) { cout << x << " "; };cout << "--->";int arr[] = {(_(args), 0)...};cout << "\n";
}void solve() {const int li = 1000000;int bn = 0, bd = 1;for (int d = 1; d <= li; ++d) {int n = (3 * d - 1) / 7;if (__gcd(n, d) == 1) {if (static_cast<long long>(n) * bd > static_cast<long long>(bn) * d) {bn = n;bd = d;}}}_(bn, bd);}int main() {int tt = 1;// cin >> tt;while (tt--) {solve();}}