You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 1292. 哥德巴赫猜想

一、题目描述

哥德巴赫猜想的内容如下:

任意一个大于 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,输出 ba 最大的一组。

若无解,输出 Goldbach's conjecture is wrong.。

数据范围 6≤n<10^6

输入样例

8
20
42
0

输出样例:

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

		
#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]数组发挥巨大作用
  • ④ 找到的第一个就是结果

四、实现代码

#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;
}