2019徐州ネットワークゲームH.function

問題の意味は:
まず、\(N-P_1 ^ = {P_2のK_1は}} ^ {K_2 \はcdots P_M K_m} ^ {\)の定義\(F(N)+ = K_1 K_2 + \ cdots K_m + \)
今計算
\ [\ sum_ {i = 1 } ^ NF(I!)\%998244353 \]を

アイデア:
最初の通知\(F \)関数このような性質を有する:\(F(AB&)= F(A)+ F(B)\)
:だから我々は簡素化が式を持って尋ねる
。(!I)。\ [\ {開始}&\ sum_ = {I} 1 ^ NF&\\ = \ sum_ 1} ^ {N-I = \ sum_ {J. 1 =整列します} ^ IF(J)\\ = &\ sum_ {i = 1} ^ n(nは-I + 1)F(I)= \\&(N + 1)\ sum_ {i = 1} ^ NF(I ) - \ sum_ {i = 1 } ^ N IF(I)\\ \端{整列} \]

ことに注意してください\(F \)は、上記の特性によれば、製品の機能ではなく、我々が発見\(\ sum_ {i = 1 } ^ NF(I)\)が実際に必要とされる\(1,2、\ cdots、nは\) インデックスと素因数の数のそれぞれ。上と上の\(N \!)質の分解を行い、我々はそれを変換することができ、ターン素数の各の寄与を考慮するだけです:\ sum_ {i = 1} ^ N- [I \((+ N-1) \ P IN] \ sum_ {K
= 1} ^ {34} \ lfloor \ FRAC {n}は{I ^ K} \ rfloor \) とそれの後半?
あるいは、上記のように、順番に考慮される各素数。素数のために仮定する(P \)\、それは、すべての寄与である\(CDOT P \ P、2、\ cdots、\ lfloor \ {N-FRAC {P}} \ rfloor \ CDOT P \) \ (F \)寄与\(1 \)は、答えは\((1 + 2 + \ cdots + \ lfloor \ FRAC {N-} {P} \ rfloor)P \) ;のための\(P ^ 2 \)それぞれのための\(F \)への貢献\(2 \)が、前に\(Pの\)時間は、それが寄与ので、一度カウントした(1 \)を\、結果は上記と同様です。

要約すると、式の最終的なプッシュは、次のように

\ [(N + 1)\ sum_ {i = 1} ^ N [iがPで\] \ sum_ {k = 1} ^ {34} \ lfloor \ FRAC {n}は{I ^ K} \ rfloor- \ sum_ {i = 1} ^ N [iがPで\] \ sum_ {k = 1} ^ {34} \ FRAC {\ lfloorの\のFRAC {n}は{I ^ K} N \ rfloor(\ lfloor \ FRAC {} { I ^ K} \ rfloor + 1)} {2} ^ iは、k個の\]

ときことを見出した(K> 1 \)を\の行に書かれた上記の式によれば、ライン上で直接暴力考え、うまく処理します。
場合\(K = 1 \)各素数のために必要とされるように、それは直接ことができる\(min25 \)ふるいは、彼の方法を実施します。
う何も詳細を感じ、それを詳細にコードを参照(min25の\を)\行に。(ただし、私は朝の調整、リニアふるいが間違って見つけることができませんでした...)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5, MOD = 998244353, inv = 499122177;

ll n, z;

bool chk[N];
int prime[N], tot;
ll p[N];
void pre() {
    for(int i = 2; i <= z; i++) {
        if(!chk[i]) {
            prime[++tot] = i;
            p[tot] = (p[tot - 1] + i) % MOD;
        }
        for(int j = 1; j <= tot && 1ll * i * prime[j] <= z; j++) {
            chk[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}

ll w[N], g1[N], g2[N];
int ind[N], ind2[N];
int cnt;
void calc_g() {
    for(ll i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i);
        w[++cnt] = n / i;
        if(w[cnt] <= z) ind[w[cnt]] = cnt;
        else ind2[n / w[cnt]] = cnt;
        g1[cnt] = (w[cnt] - 1) % MOD;
        g2[cnt] = w[cnt] % MOD * ((w[cnt] + 1) % MOD) % MOD * inv % MOD - 1;
    }
    for(int i = 1; i <= tot; i++) {
        for(int j = 1; j <= cnt && 1ll * prime[i] * prime[i] <= w[j]; j++) {
            ll tmp = w[j] / prime[i], k;
            if(tmp <= z) k = ind[tmp]; else k = ind2[n / tmp];
            g1[j] -= (g1[k] - i + 1) % MOD;
            g2[j] -= 1ll * (p[i] - p[i - 1]) * (g2[k] - p[i - 1]) % MOD;
            g1[j] %= MOD; g2[j] %= MOD;
            if(g1[j] < 0) g1[j] += MOD;
            if(g2[j] < 0) g2[j] += MOD;
        }
    }
}

ll work() {
    ll ans = 0;
    for(ll i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i);
        ll l = ((i - 1 <= z) ? ind[i - 1] : ind2[(n / (i - 1))]);
        ll r = ((j <= z) ? ind[j] : ind2[n / j]);
        ans += (n / i) % MOD * ((n + 1) % MOD) % MOD * (g1[r] - g1[l]) % MOD;
        ans -= (n / i) % MOD * ((n / i + 1) % MOD) % MOD * inv % MOD * (g2[r] - g2[l]) % MOD;
        ans = (ans % MOD + MOD) % MOD;
    }
    for(int i = 1; i <= tot; i++) {
        ll prim = prime[i];
        for(; prim * prime[i] <= n;) {
            prim *= prime[i];
            ans += (n + 1) % MOD * ((n / prim) % MOD) % MOD;
            ans %= MOD;
            ans -= (n / prim) % MOD * (n / prim + 1) % MOD * inv % MOD * prim % MOD;
            ans %= MOD;
        }
    }
    if(ans < 0) ans += MOD;
    return ans;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> n; z = sqrt(n) + 1;
    pre();
    calc_g();
    cout << work();
    return 0;
}

おすすめ

転載: www.cnblogs.com/heyuhhh/p/11517015.html