2019徐州网络赛 H.function

匿名 (未验证) 提交于 2019-12-03 00:03:02

题意:
先有\(n=p_1^{k_1}p_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)\)
那么我们化简所求式子有:
\[ \begin{aligned} &\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)\\ \end{aligned} \]

注意\(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\frac{n}{i^k}\rfloor\)
那后半部分呢?
还是像上面一样,每个质数依次考虑。假设对于质数\(p\)而言,那么所有有贡献的就是\(p,2\cdot p,\cdots,\lfloor\frac{n}{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\in P]\sum_{k=1}^{34}\lfloor\frac{n}{i^k}\rfloor-\sum_{i=1}^n[i\in P]\sum_{k=1}^{34}\frac{\lfloor\frac{n}{i^k}\rfloor(\lfloor\frac{n}{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; } 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!