結果

問題 No.3505 Sum of Prod of Root
コンテスト
ユーザー Naru820
提出日時 2026-03-17 15:15:45
言語 C++23
(gcc 15.2.0 + boost 1.89.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
TLE  
実行時間 -
コード長 3,741 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 1,504 ms
コンパイル使用メモリ 190,980 KB
実行使用メモリ 28,000 KB
最終ジャッジ日時 2026-04-17 19:40:33
合計ジャッジ時間 9,521 ms
ジャッジサーバーID
(参考情報)
judge3_1 / judge1_1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample -- * 1
other AC * 3 TLE * 2 -- * 8
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

// gemini 3.1proのテスト
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

long long MOD = 998244353;

// 繰り返し二乗法による累乗と逆元
long long power(long long base, long long exp) {
    long long res = 1;
    base %= MOD;
    while (exp > 0) {
        if (exp % 2 == 1) res = (res * base) % MOD;
        base = (base * base) % MOD;
        exp /= 2;
    }
    return res;
}
long long modInverse(long long n) { return power(n, MOD - 2); }

long long inv2, inv6, inv4, inv30;
void initInverses() {
    inv2 = modInverse(2);
    inv6 = modInverse(6);
    inv4 = modInverse(4);
    inv30 = modInverse(30);
}

// べき乗和の公式
long long S2(long long x) {
    x %= MOD;
    return x * (x + 1) % MOD * (2 * x + 1) % MOD * inv6 % MOD;
}
long long S3(long long x) {
    x %= MOD;
    long long res = x * (x + 1) % MOD * inv2 % MOD;
    return res * res % MOD;
}
long long S4(long long x) {
    x %= MOD;
    long long res = x * (x + 1) % MOD * (2 * x + 1) % MOD;
    long long term = (3 * x % MOD * x % MOD + 3 * x % MOD - 1 + MOD) % MOD;
    return res * term % MOD * inv30 % MOD;
}

// S(M) = \sum_{i=1}^M i * floor(sqrt(i))
long long S(long long M) {
    if (M <= 0) return 0;
    long long V = sqrt(M);
    while ((V + 1) * (V + 1) <= M) V++;
    while (V * V > M) V--;
    
    long long v1 = V - 1;
    long long part1 = (2 * S4(v1) + 3 * S3(v1) + S2(v1)) % MOD;
    
    long long M_mod = M % MOD;
    long long V2_mod = (V % MOD) * (V % MOD) % MOD;
    long long count = (M_mod - V2_mod + 1 + MOD) % MOD;
    long long sum_i = (V2_mod + M_mod) % MOD * count % MOD * inv2 % MOD;
    
    long long part2 = (V % MOD) * sum_i % MOD;
    
    return (part1 + part2) % MOD;
}

// h(L) = \prod_{k=3}^{60} floor(L^{1/k})
long long calc_h(long long L) {
    long long res = 1;
    for (int k = 3; k <= 60; ++k) {
        long long r = max(1LL, (long long)round(pow(L, 1.0 / k)));
        while (true) {
            __int128 p = 1; bool over = false;
            for (int i = 0; i < k; ++i) { p *= r; if (p > L) { over = true; break; } }
            if (over) { r--; } else {
                __int128 p2 = 1; bool over2 = false; long long rp1 = r + 1;
                for (int i = 0; i < k; ++i) { p2 *= rp1; if (p2 > L) { over2 = true; break; } }
                if (!over2) r++; else break;
            }
        }
        r %= MOD;
        if (r == 1) break; // r=1なら以降のkもすべて1なので打ち切る
        res = res * r % MOD;
    }
    return res;
}

int main() {
    initInverses();
    long long N;
    if (!(cin >> N)) return 0;
    
    // 変化点 (a^k) を列挙
    vector<long long> bounds;
    for (long long a = 2; a <= 1000000; ++a) {
        long long p = a * a * a;
        if (p > N) break;
        while (true) {
            bounds.push_back(p);
            if (N / a < p) break;
            p *= a;
        }
    }
    bounds.push_back(1);
    bounds.push_back(N + 1);
    
    // ソート&重複削除
    vector<long long> valid_bounds;
    for(long long b : bounds) {
        if (b <= N + 1) valid_bounds.push_back(b);
    }
    sort(valid_bounds.begin(), valid_bounds.end());
    valid_bounds.erase(unique(valid_bounds.begin(), valid_bounds.end()), valid_bounds.end());
    
    // 区間ごとに和を計算
    long long ans = 0;
    for (size_t i = 0; i < valid_bounds.size() - 1; ++i) {
        long long L = valid_bounds[i];
        long long R = valid_bounds[i+1] - 1;
        if (L > R) continue;
        
        long long h_val = calc_h(L);
        long long sum_interval = (S(R) - S(L - 1) + MOD) % MOD;
        
        ans = (ans + h_val * sum_interval) % MOD;
    }
    
    cout << ans << "\n";
    return 0;
}
0