题目要求给定一个数$N$,$N \leq 2^{32} - 1$,求
$$ans1 = \sum_{i = 1}^N \phi (i), ans2 = \sum_{i = 1}^N \mu (i) $$
——蛤?这个怎么做?我只知道线性筛。。。
先介绍$O(N)$的算法——线性筛。
由于Euler函数和Mobius函数都是积性函数(即对于$(a, b) = 1$, $f(ab) = f(a)f(b)$),可以利用类似贾志鹏线性筛的方法$O(n)$筛出1到$N$所有数的函数值。
1 #include<cstdio> 2 #include<cstring> 3 typedef long long LL; 4 const int N = 1000050; 5 LL phi[N], mobius[N]; 6 int pr[300000]; 7 void calc(int n) { //计算[1, n]的phi值及mobius值 8 memset(phi, -1, sizeof phi); 9 memset(mobius, -1, sizeof mobius); 10 int prnum = 0, i, j; 11 phi[1] = mobius[1] = 1; 12 for (i = 2; i < n; ++i) { 13 if (phi[i] < 0) { 14 pr[prnum++] = i; 15 phi[i] = i - 1; 16 mobius[i] = -1; 17 } 18 for (j = 0; j < prnum && (LL)i * pr[j] <= n; ++j) { 19 if (i % pr[j]) { 20 phi[i * pr[j]] = phi[i] * (pr[j] - 1); 21 mobius[i * pr[j]] = -mobius[i]; 22 } else { 23 phi[i * pr[j]] = phi[i] * pr[j]; 24 mobius[i * pr[j]] = 0; 25 break; 26 } 27 } 28 } 29 } 30 int main() { //O(n) - O(1) 31 calc(1000000); 32 for (int i = 2; i <= 1000000; ++i) { 33 phi[i] += phi[i - 1]; 34 mobius[i] += mobius[i - 1]; 35 } 36 long long ans1 = 0, ans2 = 0; 37 int T, n; 38 scanf("%d", &T); 39 while (T--) { 40 scanf("%d", &n); 41 printf("%lld %lld", phi[n], mobius[n]); 42 } 43 return 0; 44 }