题目大意:给你$n$,求:
$$
sumlimits_{i=1}^nvarphi(i),sumlimits_{i=1}^nmu(i)
$$
最多$10$组数据,$nleqslant2^{31}-1$
题解:杜教筛,用来求$sumlimits_{i=1}^nf(i)$的,其中$f$是某个特殊函数。
若我们可以找到一个函数$g$,使得$g,f*g$两个函数的前缀和十分好算($g*f$表示$g$和$f$的狄利克雷卷积),就可在$O(n^{frac 23})$的复杂度内求出我们要的东西。令$S(n)=sumlimits_{i=1}^nf(i)$
$$
egin{align*}
sumlimits_{i=1}^n(g*f)(i)&=sumlimits_{i=1}^nsumlimits_{d|i}g(d)fleft(dfrac id
ight)\
&=sumlimits_{d=1}^ng(d)sumlimits_{i=1,d|i}^nfleft(dfrac id
ight)\
&=sumlimits_{d=1}g(d)Sleft(leftlfloordfrac nd
ight
floor
ight)
end{align*}\
g(1)S(n)=sumlimits_{i=1}^n(f*g)(i)-sumlimits_{i=2}^ng(i)Sleft(leftlfloordfrac ni
ight
floor
ight)
$$
然后线性筛求出前$n^{frac23}$项,剩余的递归+整除分块计算,需要记忆化。
$$
sumlimits_{i=1}^nvarphi(i):\
ecausevarphi*I=id\
herefore S(n)=frac{n(n+1)}{2}-sum_{i=2}^nSleft(leftlfloordfrac n i
ight
floor
ight)
$$
$$
sumlimits_{i=1}^nmu(i):\
ecausemu*I=1\
herefore S(n)=1-sum_{i=2}^nSleft(leftlfloorfrac n i
ight
floor
ight)
$$
注意这道题中$nleqslant2^{31}-1$,$+1$后会爆$int$,所以整除分块的时候要用$unsigned$
卡点:无
C++ Code:
#include <cstdio> #include <iostream> #include <algorithm> #include <unordered_map> const int R = 1 << 22 | 1; int plist[R >> 3], ptot; bool notp[R]; long long phi[R], mu[R]; void sieve() { phi[1] = mu[1] = 1; for (int i = 2; i < R; ++i){ if (!notp[i]) plist[ptot++]=i, phi[i] = i - 1, mu[i] = -1; for(int j = 0, t; (t = i * plist[j]) < R; ++j){ notp[t] = true; if(i % plist[j] == 0) { phi[t] = phi[i] * plist[j]; mu[t] = 0; break; } phi[t] = phi[i] * phi[plist[j]]; mu[t] = -mu[i]; } } for (int i = 2; i < R; ++i) phi[i] += phi[i - 1], mu[i] += mu[i - 1]; } std::unordered_map<unsigned, long long> Phi, Mu; long long sphi(unsigned n) { if (n < R) return phi[n]; if (Phi.count(n)) return Phi[n]; long long &t = Phi[n]; for (unsigned l = 2, r; l <= n; l = r + 1) { r = n / (n / l); t += (r - l + 1) * sphi(n / l); } return t = static_cast<long long> (n + 1) * n / 2 - t; } long long smu(unsigned n) { if (n < R) return mu[n]; if (Mu.count(n)) return Mu[n]; long long &t = Mu[n]; for (unsigned l = 2, r; l <= n; l = r + 1) { r = n / (n / l); t += (r - l + 1) * smu(n / l); } return t = 1 - t; } int T; int main() { std::ios::sync_with_stdio(false), std::cin.tie(0), std::cin.tie(0); sieve(); std::cin >> T; while (T --> 0) { static unsigned n; std::cin >> n; std::cout << sphi(n) << ' ' << smu(n) << ' '; } return 0; }