AtCoder Beginner Contest 340 F

https://atcoder.jp/contests/abc340/tasks/abc340_f

 |AY - BX| = 2を解くだけですが、けっこういやらしいですね。

// F - S = 1
#![allow(non_snake_case)]

use std::cmp::min;


//////////////////// 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()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}

// ax = by + 1 (a, b > 0)
fn linear_diophantine(a: i64, b: i64) -> Option<(i64, i64)> {
    if a == 1 {
        return Some((1, 0))
    }
    
    let q = b / a;
    let r = b % a;
    if r == 0 {
        return None
    }
    let (x1, y1) = linear_diophantine(r, a)?;
    Some((-q * x1 - y1, -x1))
}


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

fn read_input() -> (i64, i64) {
    let v: Vec<i64> = read_vec();
    let (X, Y) = (v[0], v[1]);
    (X, Y)
}

fn shift_core(a: i64, b: i64, X: i64, Y: i64) -> (i64, i64) {
    let mut min_e = min(a.abs(), b.abs());
    let (mut a1, mut b1) = (a, b);
    loop {
        a1 += X;
        b1 += Y;
        if min(a1.abs(), b1.abs()) >= min_e {
            a1 -= X;
            b1 -= Y;
            break
        }
        min_e = min(a1.abs(), b1.abs());
    }
    let (mut a2, mut b2) = (a, b);
    loop {
        a2 -= X;
        b2 -= Y;
        if min(a2.abs(), b2.abs()) >= min_e {
            break
        }
        min_e = min(a2.abs(), b2.abs());
        a1 = a2;
        b1 = b2
    }
    (a1, b1)
}

const D: i64 = 10_i64.pow(18);

fn select((A1, B1): (i64, i64), (A2, B2): (i64, i64)) -> Option<(i64, i64)> {
    let min1 = min(A1.abs(), B1.abs());
    let min2 = min(A2.abs(), B2.abs());
    if min1 > D {
        if min2 > D {
            None
        }
        else {
            Some((A2, B2))
        }
    }
    else {
        if min1 < min2 {
            Some((A1, B1))
        }
        else {
            Some((A2, B2))
        }
    }
}

fn XOR(b1: bool, b2: bool) -> bool {
    b1 != b2
}

fn shift(a: i64, b: i64, X: i64, Y: i64) -> Option<(i64, i64)> {
    if XOR(X > 0, Y > 0) {  // different sign
        select(shift_core(a, -b, X, Y), shift_core(-a, b, X, Y))
    }
    else {
        select(shift_core(a, b, X, Y), shift_core(-a, -b, X, Y))
    }
}

fn F_core(X: i64, Y: i64) -> Option<(i64, i64)> {
    if Y == 0 {
        if X.abs() <= 2 {
            return Some((0, 2 / X))
        }
        else {
            return None
        }
    }
    else if X == 0 {
        if Y.abs() <= 2 {
            return Some((2 / Y, 0))
        }
        else {
            return None
        }
    }
    else if X % 2 == 0 && Y % 2 == 0 {
        let (a, b) = linear_diophantine(Y.abs()/2, X.abs()/2)?;
        shift(a, b, X, Y)
    }
    else {
        let (a, b) = linear_diophantine(Y.abs(), X.abs())?;
        shift(a*2, b*2, X, Y)
    }
}

fn F(X: i64, Y: i64) {
    if let Some((A, B)) = F_core(X, Y) {
        println!("{} {}", A, B)
    }
    else {
        println!("-1")
    }
}

fn main() {
    let (X, Y) = read_input();
    F(X, Y)
}