杜教筛

其实不是什么特别毒瘤的东西

用于求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 }
杜教筛

 

posted @ 2018-08-03 21:53  hjmmm  阅读(190)  评论(0编辑  收藏  举报