Atcoder abc333
https://atcoder.jp/contests/abc333
G - Nearest Fraction
给一个(0,1)之间,不超过18位的小数r
求 一个分母<= N的最接近它的分数,如果有多个则输出最小的
n 1e10
2s
1024mb
我的思路
首先r肯定是通过字符串读取变成 整数/10的幂次
然后可以用 连分数的形式展开它
问题是这样的截断连分数因为分母<= N的限制 似乎直接截断不是最优的,二分最后一个位置的值?
例如样例$0.45, N = 5$
$\displaystyle 0.45=\frac{45}{100}=\frac{9}{20}=0+\frac{1}{\frac{20}{9}}=0+\frac{1}{2+\frac{1}{\frac{9}{2}}}=\frac{9}{20}=0+\frac{1}{\frac{20}{9}}=0+\frac{1}{2+\frac{1}{4+\frac{1}{2}}}$
这里 的 连分数是$[0,2,4,2]$
截断的话会是$\frac{1}{2},\frac{9}{4}$ 之间
而最优是$\frac{2}{5} = [0,2,2]$
所以想法是在会超过的地方 做个除法
然而 比较小数C++精度不够,用分数比较 longlong也会overflow
所以直接换语言,上python, 一次性过了
代码
https://atcoder.jp/contests/abc333/submissions/50068617
1 | r=input() |
总结
主要是之前做过project euler 066 这个题的时候,学过pell方程和连分数相关的数学知识,当时花了我 碎片的2个月时间反复的学,所以对连分数印象还很深的
这里用的性质就是,由连分数得到的渐近分数,其值是在分子或分母小于下一个渐近分数的分数中,最接近精确值的近似值。
//我看洛谷题解中有人说python甚至还有库,3行过G是吧
1 | from fractions import Fraction # 引用 |
然后 还有 Stern-Brocot 树, 也就是 每次 a/b,c/d 中间取(a+c)/(b+d), 且都是最简分数