https://atcoder.jp/contests/abc279/tasks/abc279_d
微分を使わなくても、3点の区間を倍々にしていって、3点の中で真ん中が一番時間が短ければ、そこから真ん中が一番時間が短い状態をキープしつつ区間を縮小していきます。
// Freefall #![allow(non_snake_case)] 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() } fn read_vec<T: std::str::FromStr>() -> Vec<T> { read::<String>().split_whitespace() .map(|e| e.parse().ok().unwrap()).collect() } fn read_input() -> (u64, u64) { let v = read_vec(); (v[0], v[1]) } fn time(g: u64, A: u64, B: u64) -> f64 { (A as f64) / (g as f64).sqrt() + (B * (g - 1)) as f64 } fn find_increasing_point(g2: u64, t2: f64, A: u64, B: u64) -> u64 { let g3 = g2 * 2; let t3 = time(g3, A, B); if t2 < t3 { g2 } else { find_increasing_point(g3, t3, A, B) } } fn find_min_time(g1: u64, g2: u64, g3: u64, A: u64, B: u64) -> f64 { if g1 == g2 - 1 && g2 == g3 - 1 { return time(g2, A, B) } let g4 = (g1 + g2) / 2; let g5 = (g2 + g3) / 2; let t4 = time(g4, A, B); let t2 = time(g2, A, B); let t5 = time(g5, A, B); if t2 <= t4 && t2 <= t5 { find_min_time(g4, g2, g5, A, B) } else if t4 <= t2 && t4 <= t5 { find_min_time(g1, g4, g2, A, B) } else { find_min_time(g2, g5, g3, A, B) } } fn f(A: u64, B: u64) -> f64 { let t1 = time(1, A, B); let t2 = time(2, A, B); if t1 < t2 { return t1 } let g = find_increasing_point(2, t2, A, B); find_min_time(g / 2, g, g * 2, A, B) } fn main() { let v = read_input(); println!("{}", f(v.0, v.1)) }