結果

問題 No.886 Direct
ユーザー akakimidoriakakimidori
提出日時 2021-11-29 20:03:48
言語 Rust
(1.77.0)
結果
AC  
実行時間 99 ms / 4,000 ms
コード長 6,155 bytes
コンパイル時間 1,269 ms
コンパイル使用メモリ 169,708 KB
実行使用メモリ 4,380 KB
最終ジャッジ日時 2023-09-15 09:19:05
合計ジャッジ時間 3,461 ms
ジャッジサーバーID
(参考情報)
judge12 / judge15
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,376 KB
testcase_01 AC 1 ms
4,380 KB
testcase_02 AC 1 ms
4,380 KB
testcase_03 AC 2 ms
4,380 KB
testcase_04 AC 1 ms
4,380 KB
testcase_05 AC 1 ms
4,376 KB
testcase_06 AC 1 ms
4,376 KB
testcase_07 AC 1 ms
4,376 KB
testcase_08 AC 1 ms
4,376 KB
testcase_09 AC 1 ms
4,380 KB
testcase_10 AC 1 ms
4,376 KB
testcase_11 AC 1 ms
4,376 KB
testcase_12 AC 1 ms
4,376 KB
testcase_13 AC 1 ms
4,376 KB
testcase_14 AC 1 ms
4,376 KB
testcase_15 AC 1 ms
4,380 KB
testcase_16 AC 1 ms
4,376 KB
testcase_17 AC 2 ms
4,380 KB
testcase_18 AC 4 ms
4,376 KB
testcase_19 AC 3 ms
4,380 KB
testcase_20 AC 2 ms
4,376 KB
testcase_21 AC 2 ms
4,376 KB
testcase_22 AC 3 ms
4,380 KB
testcase_23 AC 51 ms
4,376 KB
testcase_24 AC 65 ms
4,380 KB
testcase_25 AC 41 ms
4,376 KB
testcase_26 AC 46 ms
4,380 KB
testcase_27 AC 99 ms
4,380 KB
testcase_28 AC 99 ms
4,380 KB
testcase_29 AC 1 ms
4,380 KB
testcase_30 AC 1 ms
4,376 KB
testcase_31 AC 81 ms
4,376 KB
testcase_32 AC 81 ms
4,376 KB
testcase_33 AC 81 ms
4,376 KB
testcase_34 AC 81 ms
4,380 KB
testcase_35 AC 82 ms
4,380 KB
権限があれば一括ダウンロードができます
コンパイルメッセージ
warning: function `gcd` is never used
   --> Main.rs:220:4
    |
220 | fn gcd(a: usize, b: usize) -> usize {
    |    ^^^
    |
    = note: `#[warn(dead_code)]` on by default

warning: 1 warning emitted

ソースコード

diff #

// ---------- begin recurse ----------
// reference
// https://twitter.com/noshi91/status/1393952665566994434
// https://twitter.com/shino16_cp/status/1393933468082397190
pub fn recurse<A, R, F>(f: F) -> impl Fn(A) -> R
where
    F: Fn(&dyn Fn(A) -> R, A) -> R,
{
    fn call<A, R, F>(f: &F, a: A) -> R
    where
        F: Fn(&dyn Fn(A) -> R, A) -> R,
    {
        f(&|a| call(f, a), a)
    }
    move |a| call(&f, a)
}
// ---------- end recurse ----------

use std::marker::*;
use std::ops::*;

pub trait Modulo {
    fn modulo() -> u32;
}

pub struct ConstantModulo<const M: u32>;

impl<const M: u32> Modulo for ConstantModulo<{ M }> {
    fn modulo() -> u32 {
        M
    }
}

pub struct ModInt<T>(u32, PhantomData<T>);

impl<T> Clone for ModInt<T> {
    fn clone(&self) -> Self {
        Self::new_unchecked(self.0)
    }
}

impl<T> Copy for ModInt<T> {}

impl<T: Modulo> Add for ModInt<T> {
    type Output = ModInt<T>;
    fn add(self, rhs: Self) -> Self::Output {
        let mut v = self.0 + rhs.0;
        if v >= T::modulo() {
            v -= T::modulo();
        }
        Self::new_unchecked(v)
    }
}

impl<T: Modulo> AddAssign for ModInt<T> {
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs;
    }
}

impl<T: Modulo> Sub for ModInt<T> {
    type Output = ModInt<T>;
    fn sub(self, rhs: Self) -> Self::Output {
        let mut v = self.0 - rhs.0;
        if self.0 < rhs.0 {
            v += T::modulo();
        }
        Self::new_unchecked(v)
    }
}

impl<T: Modulo> SubAssign for ModInt<T> {
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}

impl<T: Modulo> Mul for ModInt<T> {
    type Output = ModInt<T>;
    fn mul(self, rhs: Self) -> Self::Output {
        let v = self.0 as u64 * rhs.0 as u64 % T::modulo() as u64;
        Self::new_unchecked(v as u32)
    }
}

impl<T: Modulo> MulAssign for ModInt<T> {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}

impl<T: Modulo> Neg for ModInt<T> {
    type Output = ModInt<T>;
    fn neg(self) -> Self::Output {
        if self.is_zero() {
            Self::zero()
        } else {
            Self::new_unchecked(T::modulo() - self.0)
        }
    }
}

impl<T> std::fmt::Display for ModInt<T> {
    fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl<T> std::fmt::Debug for ModInt<T> {
    fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl<T: Modulo> std::str::FromStr for ModInt<T> {
    type Err = std::num::ParseIntError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val = s.parse::<u32>()?;
        Ok(ModInt::new(val))
    }
}

impl<T: Modulo> From<usize> for ModInt<T> {
    fn from(val: usize) -> ModInt<T> {
        ModInt::new_unchecked((val % T::modulo() as usize) as u32)
    }
}

impl<T: Modulo> From<u64> for ModInt<T> {
    fn from(val: u64) -> ModInt<T> {
        ModInt::new_unchecked((val % T::modulo() as u64) as u32)
    }
}

impl<T: Modulo> From<i64> for ModInt<T> {
    fn from(val: i64) -> ModInt<T> {
        if val >= 0 {
            ModInt::from(val as u64)
        } else {
            -ModInt::from((-val) as u64)
        }
    }
}

impl<T> ModInt<T> {
    pub fn new_unchecked(n: u32) -> Self {
        ModInt(n, PhantomData)
    }
    pub fn zero() -> Self {
        ModInt::new_unchecked(0)
    }
    pub fn one() -> Self {
        ModInt::new_unchecked(1)
    }
    pub fn is_zero(&self) -> bool {
        self.0 == 0
    }
}

impl<T: Modulo> ModInt<T> {
    pub fn new(d: u32) -> Self {
        ModInt::new_unchecked(d % T::modulo())
    }
    pub fn pow(&self, mut n: u64) -> Self {
        let mut t = Self::one();
        let mut s = *self;
        while n > 0 {
            if n & 1 == 1 {
                t *= s;
            }
            s *= s;
            n >>= 1;
        }
        t
    }
    pub fn inv(&self) -> Self {
        assert!(!self.is_zero());
        self.pow(T::modulo() as u64 - 2)
    }
}

type M = ModInt<ConstantModulo<1_000_000_007>>;

fn read() -> (usize, usize) {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let a = s
        .trim()
        .split_whitespace()
        .flat_map(|s| s.parse::<usize>())
        .collect::<Vec<_>>();
    (a[0], a[1])
}

fn calc<F, G>(h: usize, w: usize, f: F, g: G) -> M
where
    F: Fn(usize, usize) -> M,
    G: Fn(usize, usize) -> M,
{
    assert!(h <= w);
    use std::cell::*;
    let memo = RefCell::new(std::collections::HashMap::<(usize, usize), M>::new());
    let res = recurse(|rec, (h, w): (usize, usize)| -> M {
        if let Some(v) = memo.borrow().get(&(h, w)) {
            return *v;
        }
        let mut ans = f(h, w);
        let mut l = 2;
        while l <= h {
            let r = std::cmp::min(h / (h / l), w / (w / l));
            ans -= g(l, r) * rec((h / l, w / l));
            l = r + 1;
        }
        memo.borrow_mut().insert((h, w), ans);
        ans
    })((h, w));
    res
}

fn gcd(a: usize, b: usize) -> usize {
    if b == 0 {
        a
    } else {
        gcd(b, a % b)
    }
}

// 1 <= dx < H, 1 <= dy < W, gcd(dx, dy) == 1
// となるようなdx, dy について
// (H - dx)(W - dy) の和
//

fn run() {
    let (h, w) = read();
    let mut ans = M::from(h * (w - 1) + w * (h - 1));
    if h > 1 && w > 1 {
        let (h, w) = (h.min(w), h.max(w));
        let inv6 = M::new(6).inv();
        let two = |n: usize| -> M { M::from(n * (n + 1)) * M::from(2 * n + 1) * inv6 };
        let one = |n: usize| -> M { M::from(n * (n + 1) / 2) };
        let mut add = M::zero();
        add += M::from(h * w) * calc(h - 1, w - 1, |h, w| M::from(h * w), |l, r| M::from(r - l + 1));
        add -= M::from(w) * calc(h - 1, w - 1, |h, w| M::from(w) * one(h), |l, r| one(r) - one(l - 1));
        add -= M::from(h) * calc(h - 1, w - 1, |h, w| M::from(h) * one(w), |l, r| one(r) - one(l - 1));
        add += calc(h - 1, w - 1, |h, w| one(h) * one(w), |l, r| two(r) - two(l - 1));
        ans += add + add;
    }
    println!("{}", ans);
}

fn main() {
    run();
}
0