AtCoder Beginner Contest 353 F

https://atcoder.jp/contests/abc353/tasks/abc353_f

K = 1なら単なるマンハッタン距離です。
K > 1なら、例1のように両側から大きいタイルに出て、大きなタイル間の距離を調べます。そのとき斜めの成分とx軸、y軸のどちらかに分解します。斜め成分は一つ進むごとに2回タイルを通過します。それ以外の成分はK > 2なら2つ進むごとに角のタイルを使って4回タイルを通過しますが、K = 2の場合だけはそのまま突っ切って3回タイルを通過します。

// Tile Distance
#![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()
}

fn div(n: i64, d: i64) -> i64 {
    if n < 0 {
        (n - d + 1) / d
    }
    else {
        n / d
    }
}

fn modulo(n: i64, d: i64) -> i64 {
    if n < 0 {
        let r = n % d;
        if r == 0 { r } else { r + d }
    }
    else {
        n % d
    }
}


//////////////////// Point ////////////////////

#[derive(Clone, Copy)]
struct Point {
    x: i64,
    y: i64
}

use std::ops::Sub;

impl Sub for Point {
    type Output = Self;
    
    fn sub(self, other: Self) -> Self {
        let x = self.x - other.x;
        let y = self.y - other.y;
        Point { x, y }
    }
}

impl Point {
    fn new(x: i64, y: i64) -> Point {
        Point { x, y }
    }
    
    fn read() -> Point {
        let v = read_vec();
        Point::new(v[0], v[1])
    }
}


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

fn read_input() -> (i64, Point, Point) {
    let K: i64 = read();
    let S = Point::read();
    let T = Point::read();
    (K, S, T)
}

fn F1(S: Point, T: Point) -> i64 {
    let d = S - T;
    d.x.abs() + d.y.abs()
}

fn is_large(pt: Point, K: i64) -> bool {
    (div(pt.x, K) + div(pt.y, K)) % 2 == 1
}

fn large_to_large(pt1: Point, pt2: Point, K: i64) -> i64 {
    let x1 = div(pt1.x, K);
    let y1 = div(pt1.y, K);
    let x2 = div(pt2.x, K);
    let y2 = div(pt2.y, K);
    let dx = (x1 - x2).abs();
    let dy = (y1 - y2).abs();
    let c = if K == 2 { 3 } else { 4 };
    (dx - dy).abs() * c / 2 + min(dx, dy) * 2
}

fn to_large(pt: Point, dir: i32, K: i64) -> (i64, Point) {
    if dir == 0 {
        let r = modulo(pt.x, K);
        (r + 1, Point::new(pt.x - K, pt.y))
    }
    else if dir == 1 {
        let r = modulo(pt.y, K);
        (K - r, Point::new(pt.x, pt.y + K))
    }
    else if dir == 2 {
        let r = modulo(pt.x, K);
        (K - r, Point::new(pt.x + K, pt.y))
    }
    else {
        let r = modulo(pt.y, K);
        (r + 1, Point::new(pt.x, pt.y - K))
    }
}

fn large_to_small(pt1: Point, pt2: Point, K: i64) -> i64 {
    let mut ds: Vec<i64> = vec![];
    for dir in 0..4 {
        let (d, pt3) = to_large(pt2, dir, K);
        ds.push(d + large_to_large(pt1, pt3, K))
    }
    ds.into_iter().min().unwrap()
}

fn small_to_small(pt1: Point, pt2: Point, K: i64) -> i64 {
    let mut ds: Vec<i64> = vec![F1(pt1, pt2)];
    for dir1 in 0..4 {
        for dir2 in 0..4 {
            let (d1, pt3) = to_large(pt1, dir1, K);
            let (d2, pt4) = to_large(pt2, dir2, K);
            ds.push(d1 + large_to_large(pt3, pt4, K) + d2)
        }
    }
    ds.into_iter().min().unwrap()
}

fn F2(K: i64, S: Point, T:Point) -> i64 {
    if is_large(S, K) {
        if is_large(T, K) {
            large_to_large(S, T, K)
        }
        else {
            large_to_small(S, T, K)
        }
    }
    else {
        if is_large(T, K) {
            large_to_small(T, S, K)
        }
        else {
            small_to_small(S, T, K)
        }
    }
}

fn F(K: i64, S: Point, T: Point) -> i64 {
    if K == 1 {
        F1(S, T)
    }
    else {
        F2(K, S, T)
    }
}

fn main() {
    let (K, S, T) = read_input();
    println!("{}", F(K, S, T))
}