杜教筛
其实不是什么特别毒瘤的东西
用于求F = ∑ni = 1 f(i)
然鹅F如果难算的话
就找到好计算的 G,H
使得f * g = h
那么
∑ni = 1 (f * g)(i) = ∑nj = 1 g(j) * ∑n / ik = 1 f(k)
∑ni = 1 (f * g) (i) = ∑ni = 1 h(i)
则可合并移项得出F的表示
比较常见的是 mu 和 phi
mu : F(n) = 1 - ∑ni = 2 F(n / i);
phi : F(n) = n * (n + 1) / 2 - ∑ni = 2 F(n / i);
模板题
这道题用到了一个很妙的结论
n以内两两互质的数对个数
S(n) = ∑ni = 1 ∑nj = 1 [gcd(i, j) == 1]
= ∑nd = 1 μ(d) * (n / d); 下取整
所以n以内欧拉函数和就是 ((S(n) - 1) / 2) + 1;
链接 : 【模板】杜教筛(Sum)
附上代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <map> 4 using namespace std; 5 const int N = 2e6; 6 bool ism[N]; 7 int prm[N], ps; 8 int mu[N]; 9 map<int, long long> sm; 10 11 void sieve(){ 12 mu[1] = ism[1] = 1; 13 for(int i = 2; i < N; i++){ 14 if(!ism[i]) mu[i] = -1, prm[++ps] = i; 15 for(int j = 1; j <= ps && prm[j] * i < N; j++){ 16 ism[prm[j] * i] = 1; 17 if(!(i % prm[j])) break; 18 mu[i * prm[j]] = -mu[i]; 19 } 20 } 21 for(int i = 2; i < N; i++) 22 mu[i] += mu[i - 1]; 23 } 24 25 long long sum_mu(int x){ 26 if(x < N) return mu[x]; 27 if(sm.count(x)) return sm[x]; 28 int i = 2, j; 29 long long ret = 1; 30 while(i <= x){ 31 j = x / (x / i); 32 ret -= (long long)(j - i + 1) * sum_mu(x / i); 33 i = j + 1; 34 } 35 return sm[x] = ret; 36 } 37 38 long long sum_phi(int x){ 39 long long ret = 0; 40 long long i = 1, j; 41 while(i <= x){ 42 j = x / (x / i); 43 ret += (x / i) * (x / i) * (sum_mu(j) - sum_mu(i - 1)); 44 i = j + 1; 45 } 46 return ((ret - 1) >> 1) + 1; 47 } 48 49 int main(){ 50 sieve(); 51 int T; scanf("%d", &T); 52 int x; 53 long long a1, a2; 54 while(T--){ 55 scanf("%d", &x); 56 a1 = sum_mu(x); a2 = sum_phi(x); 57 printf("%lld %lld\n", a2, a1); 58 } 59 return 0; 60 }