#![allow(dead_code, unused_imports, unused_macros, non_snake_case)] pub use __cargo_equip::prelude::*; fn main() { input! { N: i64, } // ans = (1 ..= N).map(|L| (N / L).pow(L) ).sum() // L <= sqrt(N) のときは L で考える // L > sqrt(N) のときは N/L で考える let sqrt_N = (N as f64).sqrt().ceil() as i64; // eprintln!("sqrt({N}) = {sqrt_N}"); let mut ans = 0; let mut prev_L = 0; for L in 1..=sqrt_N { ans = (ans + pow(N / L % MOD, L)) % MOD; prev_L = L; } for N_L in (1..=N / prev_L).rev() { let min_L = ((N / (N_L + 1)) + 1).max(prev_L + 1); let max_L = N / N_L; if max_L < min_L { continue; } let sum = if N_L == 1 { (max_L - min_L + 1) % MOD } else { let a0 = pow(N_L, min_L); a0 * (pow(N_L % MOD, max_L - min_L + 1) + MOD - 1) % MOD * pow((N_L - 1) % MOD, MOD - 2) % MOD }; // eprintln!("N_L={N_L}: {sum}"); ans = (ans + sum) % MOD; prev_L = max_L; } say(ans.rem_euclid(MOD)); } fn pow(mut a: i64, mut b: i64) -> i64 { let mut r = 1; while b > 0 { if b & 1 != 0 { r = (r * a) % MOD; } a = a * a % MOD; b >>= 1; } r } type Int = i64; const MOD: Int = 998244353; // const MOD: Int = 1_000_000_007; const INF: Int = 1_000_000_000_000_000_000; const YESNO: [&'static str; 2] = ["Yes", "No"]; use cmp::{self, Reverse}; use collections::*; // (BTree|Hash)(Set|Map), BinaryHeap, VecDeque, LinkedList use proconio::{ input, marker::{Bytes, Chars, Usize1}, }; use std::ops::*; use std::*; // cmp::{min, max} fn yes() { println!("{}", YESNO[0]); } fn no() { println!("{}", YESNO[1]); } fn yesno(c: bool) { println!("{}", if c { YESNO[0] } else { YESNO[1] }); } fn say(x: T) -> T { println!("{}", x); x } fn neighbor4(i: usize, j: usize, h: usize, w: usize, mut f: F) { if i > 0 { (f)(i - 1, j); } if i < h - 1 { (f)(i + 1, j); } if j > 0 { (f)(i, j - 1); } if j < w - 1 { (f)(i, j + 1); } } trait MyItertools: Iterator + Sized { fn to_vec(self) -> Vec { self.collect::>() } fn to_vec_rev(self) -> Vec { let mut v = self.collect::>(); v.reverse(); v } fn tally(self) -> HashMap where Self::Item: Copy + Eq + hash::Hash, { let mut counts = HashMap::new(); self.for_each(|item| *counts.entry(item).or_default() += 1); counts } fn count_if bool>(self, predicate: P) -> usize { self.map(predicate).filter(|&x| x).count() } fn implode(self, sep: &str) -> String where Self::Item: std::string::ToString, { self.map(|x| x.to_string()).to_vec().join(sep) } fn mex(self, gen: impl IntoIterator) -> Self::Item where Self::Item: Ord, { let mut v = self.collect::>(); v.sort(); v.dedup(); let mut it = v.into_iter(); gen.into_iter() .find(|a| { if let Some(x) = it.next() { a != &x } else { true } }) .unwrap() } } impl MyItertools for T where T: Iterator + Sized {} trait MyOrd: PartialOrd + Sized { fn chmax(&mut self, mut rhs: Self) -> bool { if self < &mut rhs { *self = rhs; true } else { false } } fn chmin(&mut self, mut rhs: Self) -> bool { if self > &mut rhs { *self = rhs; true } else { false } } } impl MyOrd for T {} // The following code was expanded by `cargo-equip`. /// # Bundled libraries /// /// - `permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)` licensed under `MIT/Apache-2.0` as `crate::__cargo_equip::crates::permutohedron` /// /// # License and Copyright Notices /// /// - `permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)` /// /// ```text /// Copyright (c) 2015-2017 Ulrik Sverdrup "bluss" /// /// Permission is hereby granted, free of charge, to any /// person obtaining a copy of this software and associated /// documentation files (the "Software"), to deal in the /// Software without restriction, including without /// limitation the rights to use, copy, modify, merge, /// publish, distribute, sublicense, and/or sell copies of /// the Software, and to permit persons to whom the Software /// is furnished to do so, subject to the following /// conditions: /// /// The above copyright notice and this permission notice /// shall be included in all copies or substantial portions /// of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF /// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED /// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A /// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT /// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY /// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION /// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR /// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER /// DEALINGS IN THE SOFTWARE. /// ``` #[cfg_attr(any(), rustfmt::skip)] #[allow(unused)] mod __cargo_equip { pub(crate) mod crates { pub mod permutohedron {use std::marker::PhantomData;pub use lexical::LexicalPermutation;mod lexical{pub trait LexicalPermutation{fn next_permutation(&mut self)->bool;fn prev_permutation(&mut self)->bool;}implLexicalPermutation for[T]where T:Ord{fn next_permutation(&mut self)->bool{if self.len()<2{return false;}let mut i=self.len()-1;while i>0&&self[i-1]>=self[i]{i-=1;}if i==0{return false;}let mut j=self.len()-1;while j>=i&&self[j]<=self[i-1]{j-=1;}self.swap(j,i-1);self[i..].reverse();true}fn prev_permutation(&mut self)->bool{if self.len()<2{return false;}let mut i=self.len()-1;while i>0&&self[i-1]<=self[i]{i-=1;}if i==0{return false;}self[i..].reverse();let mut j=self.len()-1;while j>=i&&self[j-1]{match$e{x=>if x.should_break(){return x;}}}}#[derive(Copy,Clone,Debug)]pub enum Control{Continue,Break(B),}implControl{pub fn breaking()->Control<()>{Control::Break(())}pub fn break_value(self)->Option{match self{Control::Continue=>None,Control::Break(b)=>Some(b),}}}pub trait ControlFlow{fn continuing()->Self;#[inline]fn should_break(&self)->bool{false}}impl ControlFlow for(){fn continuing(){}}implControlFlow for Control{fn continuing()->Self{Control::Continue}fn should_break(&self)->bool{if let Control::Break(_)=*self{true}else{false}}}implControlFlow for Result<(),E>{fn continuing()->Self{Ok(())}fn should_break(&self)->bool{if let Err(_)=*self{true}else{false}}}}use control::ControlFlow;pub fn heap_recursive(xs:&mut[T],mut f:F)->C where F:FnMut(&mut[T])->C,C:ControlFlow,{match xs.len(){0|1=>f(xs),2=>{try_control!(f(xs));xs.swap(0,1);f(xs)}n=>heap_unrolled_(n,xs,&mut f),}}fn heap_unrolled_(n:usize,xs:&mut[T],f:&mut F)->C where F:FnMut(&mut[T])->C,C:ControlFlow,{debug_assert!(n>=3);match n{3=>{try_control!(f(xs));xs.swap(0,1);try_control!(f(xs));xs.swap(0,2);try_control!(f(xs));xs.swap(0,1);try_control!(f(xs));xs.swap(0,2);try_control!(f(xs));xs.swap(0,1);f(xs)}n=>{for i in 0..n-1{try_control!(heap_unrolled_(n-1,xs,f));let j=if n%2==0{i}else{0};xs.swap(j,n-1);}heap_unrolled_(n-1,xs,f)}}}pub const MAXHEAP:usize=16;#[repr(C)]pub struct Heap<'a,Data:'a+?Sized,T:'a>{data:&'a mut Data,n:u32,c:[u8;MAXHEAP-1],_element:PhantomData<&'a mut T>}impl<'a,T,Data:?Sized>Heap<'a,Data,T>where Data:AsMut<[T]>{pub fn new(data:&'a mut Data)->Self{assert!(data.as_mut().len()<=MAXHEAP);Heap{data:data,c:[0;MAXHEAP-1],n:!0,_element:PhantomData,}}pub fn get(&self)->&Data{self.data}pub fn get_mut(&mut self)->&mut Data{self.data}pub fn reset(&mut self){self.n=!0;for c in&mut self.c[..]{*c=0;}}pub fn next_permutation(&mut self)->Option<&mut Data>{if self.n==!0{self.n=0;Some(self.data)}else{while 1+(self.n as usize)Iterator for Heap<'a,Data,T>where Data:AsMut<[T]>+ToOwned,{type Item=Data::Owned;fn next(&mut self)->Option{match self.next_permutation(){None=>None,Some(perm)=>Some(perm.to_owned()),}}}pub fn factorial(n:usize)->usize{(1..n+1).fold(1,|a,b|a*b)}} } pub(crate) mod macros { pub mod permutohedron {} } pub(crate) mod prelude {pub use crate::__cargo_equip::crates::*;} mod preludes { pub mod permutohedron {} } }