AtCoder Beginner Contest 333 G

https://atcoder.jp/contests/abc333/tasks/abc333_g

分母がN以下で実数rに最も近い分数を最良近似と言います。これは連分数と結びついています。
例えば、0.45を連分数で表すと、
 \displaystyle 0.45 = \frac{1}{2+\frac{1}{4+\frac{1}{2}}}
となります。これは次のように求められます。
 0.45=\frac{9}{20}の逆数を取ると \frac{20}{9}で、この整数部分は2で、小数部分は \frac{20}{9}-2=\frac{2}{9}、この逆数は \frac{9}{2}で、整数部分は4で、小数部分は \frac{9}{2}-4=\frac{1}{2}、この逆数は2なので、整数部分は2です。
この3つの整数部分、2, 4, 2を並べると連分数になります。
さて、この連分数を途中で打ち切ると、最良近似になります。計算してみると、 \frac{1}{2} \frac{4}{9} \frac{9}{20}となります。この計算は、整数部分を c_1, c_2, \cdots n_0=1, n_1=0, d_0=0, d_1=1とすると、
 n_i = c_{i-1}n_{i-1}+n_{i-2}
 d_i = c_{i-1}d_{i-1}+d_{i-2}
としたとき、 \frac{n_i}{d_i}が最良近似になります。
ただし、 c_{i-1} 1 \le c \lt c_{i-1}となるcで置き換えても最良近似になります。
Rustではi128があるので、これを使った分数構造体を作ればオーバーフローせずに計算できますね。

// Nearest Fraction
#![allow(non_snake_case)]


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}


//////////////////// process ////////////////////

#[derive(Clone, Copy)]
struct Fraction {
    num: i128,
    den: i128
}

use std::ops::{Add, Sub};

impl Add for Fraction {
    type Output = Self;
    
    fn add(self, other: Self) -> Self {
        let num = self.num * other.den + other.num * self.den;
        let den = self.den * other.den;
        Fraction::new(num, den)
    }
}

impl Sub for Fraction {
    type Output = Self;
    
    fn sub(self, other: Self) -> Self {
        let num = self.num * other.den - other.num * self.den;
        let den = self.den * other.den;
        Fraction::new(num, den)
    }
}

impl std::cmp::PartialOrd for Fraction {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        let num1 = self.num * other.den;
        let num2 = other.num * self.den;
        num1.partial_cmp(&num2)
    }
}

impl std::cmp::PartialEq for Fraction {
    fn eq(&self, other: &Self) -> bool {
        let num1 = self.num * other.den;
        let num2 = other.num * self.den;
        num1 == num2
    }
}


impl Fraction {
    fn new(num: i128, den: i128) -> Fraction {
        let d = Fraction::gcd(num, den);
        Fraction { num: num/d, den: den/d }
    }
    
    fn gcd(n: i128, m: i128) -> i128 {
        if m == 0 { n.abs() } else { Self::gcd(m, n % m) }
    }
    
    fn from_int(n: i128) -> Fraction {
        Fraction { num: n, den: 1 }
    }
    
    fn inverse(&self) -> Fraction {
        Fraction { num: self.den, den: self.num }
    }
}


//////////////////// process ////////////////////

fn read_input() -> (Fraction, i128) {
    let s: String = read();
    let s1 = &s[2..];
    let num: i128 = s1.parse().unwrap();
    let den: i128 = 10i128.pow(s1.len() as u32);
    let r = Fraction::new(num, den);
    let N: i128 = read();
    (r, N)
}

fn nearer(f1: Fraction, f2: Fraction, f: Fraction) -> Fraction {
    if f2 < f1 {
        nearer(f2, f1, f)
    }
    else if f <= f1 {
        // f <= f1 <= f2
        f1
    }
    else if f2 < f {
        // f1 <= f2 < f
        f2
    }
    else {
        // f1 < f <= f2
        let d1 = f - f1;
        let d2 = f2 - f;
        if d1 <= d2 { f1 } else { f2 }
    }
}

fn middle(f1: Fraction, f2: Fraction, c: i128) -> Fraction {
    let num = f1.num * c + f2.num;
    let den = f1.den * c + f2.den;
    Fraction::new(num, den)
}

fn nearest_fraction(r: Fraction, N: i128, r1: Fraction,
                    f1: Fraction, f2: Fraction) -> Fraction {
    let r2 = r1.inverse();
    let c = r2.num / r2.den;
    let f3 = middle(f2, f1, c);
    if f3.den >= N {
        let c1 = (N - f1.den) / f2.den;
        let f = middle(f2, f1, c1);
        nearer(f, f2, r)
    }
    else {
        nearest_fraction(r, N, r2 - Fraction::from_int(c), f2, f3)
    }
}

fn F(r: Fraction, N: i128) -> Fraction {
    if r.den <= N {
        return r
    }
    else {
        nearest_fraction(r, N, r, Fraction { num: 1, den: 0 },
                                    Fraction { num: 0, den: 1 })
    }
}

fn main() {
    let (r, N) = read_input();
    let frac = F(r, N);
    println!("{} {}", frac.num, frac.den)
}