Files
python/TangDou/AcWing/EulerFunction/874.md
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

116 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

##[$AcWing$ $874.$ 筛法求欧拉函数](https://www.acwing.com/problem/content/876/)
### 一、题目描述
给定一个正整数 $n$,求 $1∼n$ 中每个数的欧拉函数之和。
**输入格式**
共一行,包含一个整数 $n$。
**输出格式**
共一行,包含一个整数,表示 $1∼n$ 中每个数的欧拉函数之和。
**数据范围**
$1≤n≤10^6$
**输入样例:**
```cpp {.line-numbers}
6
```
**输出样例:**
```cpp {.line-numbers}
12
```
### 二、线性筛法求欧拉函数
依托于线性筛法,可以顺带求出欧拉函数值。
#### ($1$) $phi[1]=1$,$φ(1)$被 **定义** 为$1$
对区间内每个数进行分情况讨论:
#### ($2$) 质数
质数$i$的欧拉函数值$phi[i]=i-1$
比如$7$,那么$1-6$当中有多少个数与$7$互质呢?显然$6$个都是嘛。
#### ($3$) 非质数
数字$i$在被$primes[j]$尝试筛的过程中:
(设 $p_j=primes[j]$,简便下面的书写)
<font color='red'>如果$i\ \% \ p_j = 0$, 那么 $phi[i * p_j] = phi[i] * p_j$</font>
**证明**:
$\because$ $i={p_1}^{\alpha_1} * {p_2}^{\alpha_2} * {p_3}^{\alpha_3} * ... *{p_j}^{\alpha_j}*...*{p_k}^{\alpha_k}$ 【算术基本定理】
$phi[i]= i * (1- \frac{1}{p_1}) * (1- \frac{1}{p_2}) * (1- \frac{1}{p_3}) * ... * (1- \frac{1}{p_j}) $ 【欧拉公式】
$p_j*i$分解质数因数的结果,只比$i$多分解了一个$p_j$,而 $i \ \% \ p_j = 0$ 说明$i$中存在$p_j$因子,只不过指数增加了$1$个。
$\therefore$ $p_j * i ={p_1}^{\alpha_1} * {p_2}^{\alpha_2} * {p_3}^{\alpha_3} * ... *{p_j}^{\alpha_j+1}*...*{p_k}^{\alpha_k}$
通过瞪眼大法观察欧拉公式可知,<font color='red'><b>欧拉公式只与质数因子相关,而与质数因子的幂次无关!</b></font> 二者的质数因子没有变化,变化的只是某个质数因子的幂次。所以:
$phi[p_j * i] =p_j * i * (1- \frac{1}{p_1}) * (1- \frac{1}{p_2}) * (1- \frac{1}{p_3}) * ... * (1- \frac{1}{p_j}) = phi[i] * p_j $
**证毕**
<font color='red'>如果$i\ \% \ p_j > 0$, 那么 $phi[i * p_j] = phi[i] * (p_j-1)$ </font>
**证明:**
$\because$ $i={p_1}^{\alpha_1} * {p_2}^{\alpha_2} * {p_3}^{\alpha_3} * ... *{p_k}^{\alpha_k} $ 【算术基本定理】
$phi[i]= i * (1- \frac{1}{p_1}) * (1- \frac{1}{p_2}) * (1- \frac{1}{p_3}) * ... * (1- \frac{1}{p_k})$【欧拉公式】
$p_j*i$分解质数因数的结果,只是比$i$多分解了一个$p_j$,而 $i \ \% \ p_j>0$ 说明$i$中不存在$p_j$这个因子,需要写上去。
$p_j * i ={p_1}^{\alpha_1} * {p_2}^{\alpha_2} * {p_3}^{\alpha_3} * ... * {p_k}^{\alpha_k} * {p_j}^{1} $
$\therefore phi[p_j * i]= p_j * i * (1- \frac{1}{p_1}) * (1- \frac{1}{p_2}) * (1- \frac{1}{p_3}) * ... * (1- \frac{1}{p_k}) * (1- \frac{1}{p_j}) $
$\therefore phi[p_j * i]= p_j * phi[i] * (1 - \frac{1}{p_j}) = phi[i] * ( p_j -1) $
**证毕**
### 三、实现代码
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
int primes[N];
int cnt;
int phi[N];
int st[N];
int res;
void get_eulers(int n) {
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes[cnt++] = i;
phi[i] = i - 1; // ①质数
}
for (int j = 0; primes[j] <= n / i; j++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
phi[t] = phi[i] * primes[j]; // ② i%pj==0
break;
} else
phi[t] = phi[i] * (primes[j] - 1); // ③i%pj>0
}
}
}
signed main() {
int n;
cin >> n;
get_eulers(n);
for (int i = 1; i <= n; i++) res += phi[i];
printf("%lld\n", res);
}
```