# 杜教筛——省选前的学习1

BZOJ 3944 ——Sum

$$ans1 = \sum_{i = 1}^N \phi (i), ans2 = \sum_{i = 1}^N \mu (i)$$

——蛤？这个怎么做？我只知道线性筛。。。

 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 } 

$$(f * g)(n) = \sum_{d \mid n} f(d)g\left(\frac n d\right)$$

1. 结合律： $\forall f, g, k \in \mathbf I, (f * g) * k = f * (g * k)$

2. 单位元： $\exists \epsilon \in \mathbf I, \forall f \in \mathbf I, f * \epsilon = \epsilon * f = f$

3. 逆元：    $\forall f \in \mathbf I, \exists f \in \mathbf I, f * g = \epsilon$

4. 封闭性： $\forall f, g \in \mathbf I, f * g \in \mathbf I$

5. 交换律： $\forall f, g \in \mathbf I, f * g = g * f$

\begin{aligned} \sum_{i = 1}^N (f * g)(i) & = \sum_{i = 1}^N \sum_{d \mid i} g(d) f\left(\frac i d\right) \\ & = \sum_{d = 1}^N g(d) \sum_{1 \leq i \leq N, d | i} f\left(\frac i d\right) \\ & = \sum_{d = 1}^N g(d) \sum_{1 \leq i \leq \lfloor \frac n d \rfloor} f(i) \\ & = \sum_{d = 1}^N g(d) S\left(\left\lfloor \frac n d \right\rfloor\right) \end{aligned}

$$\sum_{i = 1}^N (f * g)(i) = \sum_{d = 1}^N g(d) S\left(\left\lfloor \frac n d \right\rfloor\right)$$

$$\therefore $$\label{recursion} g(1)S(n) = \sum_{i = 1}^N (f * g)(i) - \sum_{i = 2}^N g(i) S\left(\left\lfloor \frac n i \right\rfloor\right)$$$$

$$O\left(\sum_{i = 1}^{\left\lfloor \sqrt n \right\rfloor} \sqrt i \right) + O\left(\sum_{i = 1}^{\left\lfloor \sqrt n \right\rfloor} \sqrt{\left\lfloor \frac n i\right\rfloor} \right)$$

$$O\left(\sum_{i = 1}^{\lfloor \sqrt n \rfloor} \lfloor \sqrt{\frac n i} \rfloor \right) \approx O\left(\int_0^{\sqrt n}\sqrt{\frac n x} dx\right) = O(n^{\frac34})$$

$$ans2(n) = 1 - \sum_{i = 2}^n ans2\left(\left\lfloor \frac n i \right\rfloor\right)$$

$$ans1(n) = \frac {n(n+1)}2 - \sum_{i = 2}^n ans1\left(\left\lfloor \frac n i \right\rfloor\right)$$

AC代码：

 1 #include<cstdio>
2 #include<cstring>
3 #include<map>
4 typedef long long LL;
5 typedef std::map<int, LL> Map;
6 Map _phi, _mu;
7 int n;
8 const int N = 5000000;
9 LL phi[N], mu[N];
10 int pr[1000000];
11 void init(int n) {                    //计算[1, n]的phi值及mu值
12   memset(phi, -1, sizeof phi);
13   memset(mu, -1, sizeof mu);
14   int prnum = 0, i, j;
15   phi[1] = mu[1] = 1;
16   phi[0] = mu[0] = 0;
17   for (i = 2; i <= n; ++i) {
18     if (phi[i] < 0) {
19       pr[prnum++] = i;
20       phi[i] = i - 1;
21       mu[i] = -1;
22     }
23     for (j = 0; j < prnum && (LL)i * pr[j] <= n; ++j) {
24       if (i % pr[j]) {
25         phi[i * pr[j]] = phi[i] * (pr[j] - 1);
26         mu[i * pr[j]] = -mu[i];
27       } else {
28         phi[i * pr[j]] = phi[i] * pr[j];
29         mu[i * pr[j]] = 0;
30         break;
31       }
32     }
33   }
34   //for (i = 1; i <= 30; ++i) {
35   //  printf("%d %d\n", i, phi[i]);
36   //}
37   for (i = 2; i <= n; ++i) {
38     phi[i] += phi[i - 1];
39     mu[i] += mu[i - 1];
40   }
41 }
42 LL CalcPhi(LL n) {
43   Map::iterator it;
44   if (n < N)
45     return phi[n];
46   if ((it = _phi.find(n)) != _phi.end())
47     return it->second;
48   LL i, last, ans = (LL)n * (n + 1) >> 1;
49   for (i = 2; i <= n; i = last + 1) {
50     last = n / (n / i);
51     ans -= (last - i + 1) * CalcPhi(n / i);
52   }
53   return _phi[n] = ans;
54 }
55 LL CalcMu(LL n) {
56   Map::iterator it;
57   if (n < N)
58     return mu[n];
59   if ((it = _mu.find(n)) != _mu.end())
60     return it->second;
61   LL i, last, ans = 1;
62   for (i = 2; i <= n; i = last + 1) {
63     last = n / (n / i);
64     ans -= (last - i + 1) * CalcMu(n / i);
65   }
66   return _mu[n] = ans;
67 }
68 int main() {
69   //freopen("sum.in", "r", stdin);
70   //freopen("sum.out", "w", stdout);
71   init(N - 1);
72   int T;
73   scanf("%d", &T);
74   while (T--) {
75     scanf("%d", &n);
76     printf("%lld %lld\n", CalcPhi(n), CalcMu(n));
77   }
78   return 0;
79 } 

posted @ 2017-03-07 15:14  _rqy  阅读(4313)  评论(7编辑  收藏  举报