Files
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

165 lines
4.6 KiB
Markdown
Raw Permalink 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$ $1292$. 哥德巴赫猜想](https://www.acwing.com/problem/content/description/1294/)
### 一、题目描述
哥德巴赫猜想的内容如下:
任意一个大于 $4$ 的偶数都可以拆成两个奇素数之和。
例如:
$8=3+5$
$20=3+17=7+13$
$42=5+37=11+31=13+29=19+23$
现在,你的任务是验证所有小于一百万的偶数能否满足哥德巴赫猜想。
**输入格式**
输入包含多组数据。
每组数据占一行,包含一个偶数 $n$。
读入以 $0$ 结束。
**输出格式**
对于每组数据,输出形如 $n = a + b$,其中 $a,b$ 是奇素数。
若有多组满足条件的 $a,b$,输出 $b−a$ 最大的一组。
若无解,输出 `Goldbach's conjecture is wrong.。`
**数据范围**
$6≤n<10^6$
**输入样例**
```cpp {.line-numbers}
8
20
42
0
```
**输出样例:**
```cpp {.line-numbers}
8 = 3 + 5
20 = 3 + 17
42 = 5 + 37
```
### 二、一些常识
- #### 欧拉筛时间复杂度
$O(n)$
- #### 自然对数$e$
自然对数$e$是一个数学常数,约等于$2.71828$。它是一个无理数,也是一个重要的数学常数。$e$是自然对数的底数,它在许多数学和科学领域中都有广泛的应用。
自然对数$e$可以通过以下级数展开来定义:
$\large e = 1 + \frac{1}{1}! + \frac{1}{2}! + \frac{1}{3}! + \frac{1}{4}! + ...$
$n!$表示$n$的阶乘。
- #### 质数个数定理
$1\sim n$之间质数的个数 **约** 是$\large \frac{n}{lgn}=\frac{n}{log_en}$
**举个例子**:$n=100$,按如下的$C++$代码+质数个数定理进行计算,结果是$21$,实际上是$25$个,两者在数量级上是一致的,但不是非常准确,只能用于估算。
$n \div lg(n) =100 \div 4.60517 = 21$
```cpp {.line-numbers}
#include <iostream>
#include <cmath>
bool is_prime(int num) {
if (num < 2) {
return false;
}
for (int i = 2; i <= sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
int main() {
int n = 100; // n的值为100
int prime_count = 0; // 质数个数的计数器
for (int i = 2; i <= n; i++) {
if (is_prime(i)) {
prime_count++;
}
}
std::cout << "质数个数: " << prime_count << std::endl;
double estimated_count = (n / log(n)); // 使用质数个数定理估计质数的个数
std::cout << "质数个数定理估计值: " << estimated_count << std::endl;
return 0;
}
```
- #### 算数基本定理
任何一个大于$1$的自然数 $N$,如果$N$不为质数,那么$N$可以唯一分解成有限个质数的乘积$N = P_1^{a_1}P_2^{a_2}P_3^{a_3}…P_n^{a_n}$,这里$P_1<P_2<P_3…<P_n$均为质数,其中指数$a_i$是正整数,这样的分解称为 $N$ 的标准分解式。
### 三、实现思路
- ① 欧拉筛求出区间内所有质数
- ② 枚举每个质数,(**注意** 要放过数字$2$,因为$2$是偶数,本题要求是奇数)
- ③ 判断$n-a$是不是也是质数,此时$st[i]$数组发挥巨大作用
- ④ 找到的第一个就是结果
### 四、实现代码
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
// 欧拉筛
const int N = 1e6 + 10;
int primes[N], cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) primes[cnt++] = i;
for (int j = 0; primes[j] * i <= n; j++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
int main() {
// 加快读入
ios::sync_with_stdio(false), cin.tie(0);
// 欧拉筛求出区间内所有质数
get_primes(N - 1); // 不能到N,因为数组下标从0开始!要不会越界~
int n;
while (cin >> n, n) {
for (int i = 1;; i++) { // 枚举每个奇数质数,不用上界,因为认为哥德巴赫猜想是正确的,肯定有解
int a = primes[i]; // primes[0]=2,因为2特殊,是质数,并且是奇数,本题要求是奇数,放过数字2
int b = n - a; // 差值
if (!st[b]) { // 差值也是质数,这个st数组用的漂亮啊,我还以为要在primes中二分呢
// 第一个找的就是最小奇数质数因子,所以相对就是最大的奇数质数因子,两者的差就是最大
printf("%d = %d + %d\n", n, a, b);
break;
}
}
}
return 0;
}
```