#include #include using namespace std; using mint = atcoder::modint998244353; int main() { // 入力の高速化 ios::sync_with_stdio(false); cin.tie(nullptr); long long N; if (!(cin >> N)) return 0; mint ans = 0; // L は 1 から N まで動く // floor(N/L) が同じ値になる区間 [l, r] ごとに計算する for (long long l = 1; l <= N; ) { long long val = N / l; // 現在の floor(N/L) の値 // val が 0 になることはないが、念のため (l <= N なので val >= 1) if (val == 0) { l++; continue; } // val が同じ値をとる右端 r を求める // r は N / val で求まる(商の列挙の典型テクニック) long long r = N / val; // 区間の長さ (項数) long long count = r - l + 1; // この区間での和は val^l + val^{l+1} + ... + val^r // これは初項 val^l, 公比 val, 項数 count の等比数列の和 mint b = val; // 公比 if (b.val() == 0) { // val が mod の倍数の場合、すべての項は 0 // (l >= 1 なので 0^l = 0) ans += 0; } else if (b.val() == 1) { // 公比が 1 の場合 (val ≡ 1 mod P) // 和は 1 * count ans += count; } else { // 等比数列の和の公式: a * (r^n - 1) / (r - 1) // 初項 a = b^l mint first_term = b.pow(l); // 分子: b^count - 1 mint numerator = b.pow(count) - 1; // 分母: b - 1 の逆元 mint denominator = (b - 1).inv(); mint range_sum = first_term * numerator * denominator; ans += range_sum; } // 次の区間の開始位置へ l = r + 1; } cout << ans.val() << endl; return 0; }