前置相关
类型积性函数(注:以下皆为完全积性函数,即无需满足 $x \perp y$ 即有 $f(x) · f(y) = f(xy)$
$\epsilon (n) = [n = 1]$
$id (n) = n$
狄利克雷卷积与莫比乌斯函数
狄利克雷卷积与欧拉函数
此处若以 $id $ 作单位元,则 $1$ 为 $\phi$ 的逆,即 $\phi * 1 = id$
证明:由 $\sum\limits_{d | n} \phi (d) = n$ ,再带回原式可证
莫比乌斯函数与欧拉函数的转化
$$
\begin{aligned} \phi * 1 &= id \ \phi * 1 * \mu &= id * \mu \ \phi * \epsilon &= id * \mu \ \phi &= \sum\limits_{d | n} \mu(d) \frac{n}{d} \ \frac{\phi}{n} &= \sum\limits_{d | n} \frac{\mu(d)}{d} \end{aligned}
$$
杜教筛
$$
\begin{aligned} \sum\limits_{i = 1}^n h(n) &= \sum\limits_{i = 1}^n \sum\limits_{d | n} g(d)f(\frac{n}{d}) \\ &= \sum\limits_{d = 1}^n g(d) \sum\limits_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} f(i) \end{aligned}
$$
- 令 $S(n) = \sum\limits_{i = 1}^n f(i)$
- 将 $d = 1$ 时的提出,再移项,得
$$
S(n) = \sum\limits_{i = 1}^n h(i) - \sum\limits_{d = 2}^n g(d)S(\left\lfloor\frac{n}{d}\right\rfloor)
$$
- 那么预处理 $h, g$ 的前缀和(一般预处理 $n^{\frac{2}{3}}$ 个?),再递归整除分块即可处理,不过一般 $h, g$ 需要自己配
- 但实际上并不需要用 $\text{unordered_map}$ 来记忆化,设题目给定 $N$,当前递归到 $n$,则 $n$ 的答案可以被 $N / n$ 记录,也就是用 $visit(\lfloor\frac{N}n\rfloor)$ 来判断是否已被搜过,下面给出别人的简单证明为什么不会判重
例
求$\sum\limits_{i = 1}^n \mu(i), \sum\limits_{i = 1}^n \phi(i)$
由 $\mu * 1 = \epsilon$ ,可令 $g = 1, h = \epsilon$ ,那么得到
$$
S(n) = 1 - \sum\limits_{d = 2}^n S(\left\lfloor\frac{n}{d}\right\rfloor)
$$
求 $\sum \phi$ 同理
求$\sum\limits_{i = 1}^n i \phi(i) (需要用配的)$
$$
h(n) = \sum\limits_{d | n} d \phi(d) g(\frac{n}{d})
$$
希望将 $d$ 消去,故配 $g = id$ ,得 $h(n) = n^2$
$$
S(n) = \sum\limits_{i = 1}^n i - \sum\limits_{d = 2}^n d S(\left\lfloor\frac{n}{d}\right\rfloor)
$$
即可解
代码(求解$\sum \mu, \sum \phi$ )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include <iostream> #include <cstdio> #include <cstring> #include <tr1/unordered_map>
using namespace std;
typedef long long LL;
const int MAXN = 5e06 + 10; const int MAXM = 3000 + 10;
int prime[MAXN / 10]; int vis[MAXN]= {0}; int pcnt = 0; int mu[MAXN]= {0}; LL phi[MAXN]= {0}; int sumu[MAXN]= {0}; LL sumphi[MAXN]= {0}; const int MAX = 4e06 + 5e05; void linear_sieve () { mu[1] = phi[1] = 1; for (int i = 2; i <= MAX; i ++) { if (! vis[i]) { prime[++ pcnt] = i; mu[i] = - 1, phi[i] = i - 1; } for (int j = 1; j <= pcnt && i * prime[j] <= MAX; j ++) { vis[i * prime[j]] = 1; if (! (i % prime[j])) { phi[i * prime[j]] = phi[i] * prime[j]; break; } mu[i * prime[j]] = - mu[i]; phi[i * prime[j]] = phi[i] * (prime[j] - 1); } } for (int i = 1; i <= MAX; i ++) { sumu[i] = sumu[i - 1] + mu[i]; sumphi[i] = sumphi[i - 1] + phi[i]; } }
int T;
int N; int mapmu[MAXM]; LL maphi[MAXM]; bool vmu[MAXM]= {false}, vphi[MAXM]= {false};
int mu_sieve (int n) { if (n <= MAX) return sumu[n]; if (vmu[N / n]) return mapmu[N / n]; int total = 1; for (int l = 2, r; l <= n; l = r + 1) { r = n / (n / l); total -= (r - l + 1) * mu_sieve (n / l); } vmu[N / n] = true; return mapmu[N / n] = total; } LL phi_sieve (int n) { if (n <= MAX) return sumphi[n]; if (vphi[N / n]) return maphi[N / n]; LL total = n * 1ll * (n + 1) / 2ll; for (int l = 2, r; l <= n; l = r + 1) { r = n / (n / l); total -= 1ll * (r - l + 1) * phi_sieve (n / l); } vphi[N / n] = true; return maphi[N / n] = total; }
int main () { linear_sieve (); scanf ("%d", & T); for (int Case = 1; Case <= T; Case ++) { memset (vmu, false, sizeof (vmu)); memset (vphi, false, sizeof (vphi)); scanf ("%d", & N); LL ans1 = phi_sieve (N); int ans2 = mu_sieve (N); printf ("%lld %d\n", ans1, ans2); }
return 0; }
|