2019徐州网络赛 H.function

Posted heyuhhh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019徐州网络赛 H.function相关的知识,希望对你有一定的参考价值。

题意:
先有\(n=p_1^k_1p_2^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)\)
那么我们化简所求式子有:
\[ \beginaligned &\sum_i=1^nf(i!)\=&\sum_i=1^n\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)\\endaligned \]

注意\(f\)并不是积性函数,但是我们根据上面的性质,发现\(\sum_i=1^nf(i)\)其实求的就是\(1,2,\cdots,n\)中,每个数的质因子指数和。就和对\(n!\)做质因子分解一样,我们只需要依次考虑每个素数的贡献,那么就可以化为:\((n+1)\sum_i=1^n[i\in P]\sum_k=1^34\lfloor\fracni^k\rfloor\)
那后半部分呢?
还是像上面一样,每个质数依次考虑。假设对于质数\(p\)而言,那么所有有贡献的就是\(p,2\cdot p,\cdots,\lfloor\fracnp\rfloor \cdot p\),每个\(f\)的贡献为\(1\),那么答案就是\((1+2+\cdots+\lfloor\fracnp\rfloor)p\);对于\(p^2\)而言,每个\(f\)的贡献为\(2\),但是之前在\(p\)的时候已经算上一次,所以贡献就为\(1\)了,那么结果就和上面的差不多。

总结一下,最后推得的式子就为:

\[ (n+1)\sum_i=1^n[i\in P]\sum_k=1^34\lfloor\fracni^k\rfloor-\sum_i=1^n[i\in P]\sum_k=1^34\frac\lfloor\fracni^k\rfloor(\lfloor\fracni^k\rfloor+1)2i^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;

以上是关于2019徐州网络赛 H.function的主要内容,如果未能解决你的问题,请参考以下文章

2019.09.072019徐州网络赛

2019 徐州网络赛 center

2019徐州网络赛

query 2019徐州网络赛(树状数组)

2019徐州网络赛 I J M

2019徐州网络赛 XKC's basketball team 线段树