https://atcoder.jp/contests/abc414/tasks/abc414_e
bとcを決めると取り得るaの個数が決まります。例えば、なら、
だから9個です。一般には
個になります。なので組合せの個数は、
となります。とおけば、
となります。内側の和は分母がbで分子は連続でb-1個あるので、値は2つ以下です。小さいほうをqとおいて頑張って計算するととなります。ただし、qが一つのときは2種類あって、分子の一番小さい値がqで割り切れるときは1増しになるので調整が必要です。
例によって、bが大きいときには同じqがいくつか続くのでまとめて計算出来ての計算量になります。
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)) }