以下の内容はhttps://inamori.hateblo.jp/entry/2025/07/16/213007より取得しました。


AtCoder Beginner Contest 414 E

https://atcoder.jp/contests/abc414/tasks/abc414_e

bとcを決めると取り得るaの個数が決まります。例えば、 N=100, b=10, c=1なら、 a = 11, 21, \cdots, 91だから9個です。一般には \frac{N-c}{b}個になります。なので組合せの個数は、

 \displaystyle \sum_{b=2}^N{\sum_{c=1}^{b-1}{\frac{N-c}{b}}}

となります。 d \equiv N - cとおけば、

 \displaystyle \sum_{b=2}^N{\sum_{d=N-b+1}^{N-1}{\frac{d}{b}}}

となります。内側の和は分母がbで分子は連続でb-1個あるので、値は2つ以下です。小さいほうをqとおいて頑張って計算すると N - b - qとなります。ただし、qが一つのときは2種類あって、分子の一番小さい値がqで割り切れるときは1増しになるので調整が必要です。
例によって、bが大きいときには同じqがいくつか続くのでまとめて計算出来て O(\sqrt{N})の計算量になります。
Pythonなら簡単ですが、Rustだと難しいですね。この問題の場合、最初からi128でやればよかったかもしれません。

// Count A%B=C
#![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()
}

fn int_sqrt(n: i64) -> i64 {
    let mut x = (n + 1) / 2;
    loop {
        let x1 = (x + n / x) / 2;
        if x1 >= x {
            return x
        }
        x = x1
    }
}

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

fn inverse<const D: i64>(a: i64) -> i64 {
    let (x, _y) = linear_diophantine(a, D).unwrap();
    x.rem_euclid(D)
}


//////////////////// ModInt ////////////////////

use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Sub, SubAssign,
               Mul, MulAssign, Div, DivAssign, Neg, Rem};

#[derive(Copy, Clone)]
struct ModInt<const D: i64>(i64);

impl<const D: i64> From<i64> for ModInt<D> {
    fn from(x: i64) -> Self {
        Self(x.rem_euclid(D))
    }
}
impl<const D: i64> PartialEq for ModInt<D> {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

impl<const D: i64> PartialEq<i64> for ModInt<D> {
    fn eq(&self, other: &i64) -> bool {
        self.0 == *other
    }
}

impl<const D: i64> Eq for ModInt<D> {}

impl<const D: i64> PartialOrd for ModInt<D> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<const D: i64> Ord for ModInt<D> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<const D: i64> Add for ModInt<D> {
    type Output = Self;
    
    fn add(self, other: Self) -> Self {
        Self((self.0 + other.0) % D)
    }
}

impl<const D: i64> Add<i64> for ModInt<D> {
    type Output = Self;
    
    fn add(self, other: i64) -> Self {
        Self((self.0 + other) % D)
    }
}

impl<const D: i64> Add<ModInt<D>> for i64 {
    type Output = ModInt<D>;
    
    fn add(self, other: ModInt<D>) -> ModInt<D> {
        ModInt::<D>((self + other.0).rem_euclid(D))
    }
}

impl<const D: i64> AddAssign for ModInt<D> {
    fn add_assign(&mut self, other: ModInt<D>) {
        self.0 = (self.0 + other.0).rem_euclid(D)
    }
}

impl<const D: i64> AddAssign<i64> for ModInt<D> {
    fn add_assign(&mut self, other: i64) {
        self.0 = (self.0 + other).rem_euclid(D)
    }
}

impl<const D: i64> Sub for ModInt<D> {
    type Output = Self;
    
    fn sub(self, other: Self) -> Self {
        Self((self.0 - other.0).rem_euclid(D))
    }
}

impl<const D: i64> Sub<i64> for ModInt<D> {
    type Output = Self;
    
    fn sub(self, other: i64) -> Self {
        Self((self.0 - other).rem_euclid(D))
    }
}

impl<const D: i64> Sub<ModInt<D>> for i64 {
    type Output = ModInt<D>;
    
    fn sub(self, other: ModInt<D>) -> ModInt<D> {
        ModInt::<D>((self - other.0).rem_euclid(D))
    }
}

impl<const D: i64> SubAssign for ModInt<D> {
    fn sub_assign(&mut self, other: Self) {
        self.0 = (self.0 - other.0).rem_euclid(D)
    }
}

impl<const D: i64> SubAssign<i64> for ModInt<D> {
    fn sub_assign(&mut self, other: i64) {
        self.0 = (self.0 - other).rem_euclid(D)
    }
}

impl<const D: i64> Mul for ModInt<D> {
    type Output = Self;
    
    fn mul(self, other: Self) -> Self {
        Self(self.0 * other.0 % D)
    }
}

impl<const D: i64> Mul<i64> for ModInt<D> {
    type Output = Self;
    
    fn mul(self, other: i64) -> Self {
        Self(self.0 * other.rem_euclid(D) % D)
    }
}

impl<const D: i64> Mul<ModInt<D>> for i64 {
    type Output = ModInt<D>;
    
    fn mul(self, other: ModInt<D>) -> ModInt<D> {
        ModInt::<D>(self * other.0 % D)
    }
}

impl<const D: i64> MulAssign for ModInt<D> {
    fn mul_assign(&mut self, other: Self) {
        self.0 = self.0 * other.0 % D
    }
}

impl<const D: i64> MulAssign<i64> for ModInt<D> {
    fn mul_assign(&mut self, other: i64) {
        self.0 = self.0 * other % D
    }
}

impl<const D: i64> Div for ModInt<D> {
    type Output = Self;
    
    fn div(self, other: Self) -> Self {
        Self(self.0 * inverse::<D>(other.0) % D)
    }
}

impl<const D: i64> Div<i64> for ModInt<D> {
    type Output = Self;
    
    fn div(self, other: i64) -> Self {
        Self(self.0 * inverse::<D>(other) % D)
    }
}

impl<const D: i64> Div<ModInt<D>> for i64 {
    type Output = ModInt<D>;
    
    fn div(self, other: ModInt<D>) -> ModInt<D> {
        ModInt::<D>(self * inverse::<D>(other.0) % D)
    }
}

impl<const D: i64> DivAssign for ModInt<D> {
    fn div_assign(&mut self, other: Self) {
        self.0 = self.0 * inverse::<D>(other.0) % D
    }
}

impl<const D: i64> DivAssign<i64> for ModInt<D> {
    fn div_assign(&mut self, other: i64) {
        self.0 = self.0 * inverse::<D>(other) % D
    }
}

impl<const D: i64> Neg for ModInt<D> {
    type Output = Self;
    
    fn neg(self) -> Self::Output {
        Self(if self.0 == 0 { 0 } else { D - self.0 })
    }
}

impl<const D: i64> Rem for ModInt<D> {
    type Output = Self;
    
    fn rem(self, other: ModInt<D>) -> ModInt<D> {
        ModInt::<D>(self.0 % other.0)
    }
}

impl<const D: i64> Rem<i64> for ModInt<D> {
    type Output = Self;
    
    fn rem(self, other: i64) -> Self {
        Self(self.0 % other)
    }
}

use std::iter::Sum;

impl<const D: i64> Sum for ModInt<D> {
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        iter.fold(Self::from(0), |acc, x| acc + x)
    }
}


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

const D: i64 = 998244353;

type IntD = ModInt::<D>;

fn F(N_: i64) -> i64 {
    let N = IntD::from(N_);
    let mut s = IntD::from(0);
    let Q = int_sqrt(N_);
    let B = (N_ + 1) / (Q + 1);
    for b in 2..B+1 {
        let q = (N_ - b + 1) / b;
        s += N - b - q;
        if (N_ + 1 - b) % b == 0 {
            s += 1
        }
    }
    for q in 0..Q {
        let b1 = (N_ + 1) / (q + 2) + 1;
        let b2 = (N_ + 1) / (q + 1);
        if q == 0 {
            s += (N - b1) * (N - b1 + 1) / 2
        }
        else {
            s += ((N - q) * 2 - (b1 + b2)) * (b2 - b1 + 1) / 2;
            if (N_ + 1 - b2) % b2 == 0 {
                s += 1
            }
        }
    }
    s.0 % D
}

fn main() {
    let N: i64 = read();
    println!("{}", F(N))
}



以上の内容はhttps://inamori.hateblo.jp/entry/2025/07/16/213007より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14