B3939 绝对素数

记录1

#include <bits/stdc++.h>
using namespace std;
bool f(int n){
	for(int i=2;i<n;i++){
		if(n%i==0) return false;
	}
	return true;
}
int re(int n){
	int m=0,t=0;
	while(n){
		t=n%10;
		m=m*10+t;
		n/=10;
	}
	return m;
}
int main() {
	int n,m;
	cin>>n>>m;
	for(int i=n;i<=m;i++){
    if(f(i)&&f(re(i))) cout<<i<<endl;
  }
  return 0;
}

本题思路

  1. 判断素数
  2. 转换数字

判断素数

因为有数据保证

输入 1 行,包含两个正整数 A 和 B。保证 10<A<B<100。

所以可以直接考虑两位数情况

bool f(int n){
	for(int i=2;i<n;i++){
		if(n%i==0) return false;
	}
	return true;
}

补充:6k±1优化法判断素数

bool isPrime6k(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i * i <= n; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) return false;
    }
    return true;
}

6k±1优化法的数学原理

所有大于3的素数均可以表示为6k±1的形式(其中k为正整数)。这一特性源于数论中对整数模6的分类:

  • 任何整数n模6的余数只能是0、1、2、3、4或5。
  • 若n ≡ 0、2、4 (mod 6),则n为偶数,大于2时必为合数。
  • 若n ≡ 3 (mod 6),则n为3的倍数,大于3时必为合数。
  • 仅当n ≡ 1或5 (mod 6)时,n可能是素数(5 ≡ -1 mod 6,故统一表示为6k±1)。

减少检查次数的原因

传统素数检查需试除所有小于√n的整数,而6k±1法通过数学性质排除了以下情况:

  • 无需检查偶数(2的倍数)。
  • 无需检查3的倍数。
  • 仅需检查6k±1形式的数,即每6个数中仅检查2个候选。

例如,检查n=37是否为素数:

  • 常规方法需试除2、3、4、5、6(共5次)。
  • 6k±1法仅需试除5(=6×1-1)和7(=6×1+1,但7²>37),实际只需检查5(1次)。

实现效率提升

对于大数n,检查次数从O(√n)降低到O(√n/3),因为:

  • 原始方法需√n次检查。
  • 优化后仅需检查1/3的数(6k±1占全部数的1/3)。

公式化表达为: 检查范围缩减至:k ≤ ⌊√n/6⌋
每次k生成两个候选除数:6k−1和6k+1。

转换数字

int re(int n){
	int m=0,t=0;
	while(n){
		t=n%10;
		m=m*10+t;
		n/=10;
	}
	return m;
}

简单的数位分离,%10相当于拿出数的尾巴,/10相当于砍掉数的尾巴

倒过来时候,通过乘10来进行扩大数的位数,然后加上尾巴数

补充

在算法竞赛和编程中,处理素数是常见的任务。以下是一些常用的处理素数的方法,条理清晰,分级明确,帮助你更好地理解和应用这些方法。

1. 判断一个数是否为素数

1.1 方法1:暴力法
  • 步骤

    1. 检查从2到 n​ 的所有数是否能整除 n。

    2. 如果没有找到能整除 n 的数,则 n 是素数。

  • 代码示例

#include <iostream>
#include <cmath>
using namespace std;

bool isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i * i <= n; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) return false;
    }
    return true;
}

int main() {
    int n;
    cout << "Enter a number: ";
    cin >> n;
    if (isPrime(n)) {
        cout << n << " is a prime number." << endl;
    } else {
        cout << n << " is not a prime number." << endl;
    }
    return 0;
}

2. 生成一定范围内的所有素数

2.1 方法1:埃拉托斯特尼筛法(Sieve of Eratosthenes)
  • 步骤

    1. 创建一个布尔数组 is_prime,大小为 n+1,并将所有元素初始化为 true

    2. 将0和1标记为 false

    3. 从2开始,逐步标记所有素数的倍数为 false

    4. 遍历数组,所有值为 true 的索引即为素数。

  • 代码示例

#include <iostream>
#include <vector>
using namespace std;

vector<int> sieveOfEratosthenes(int n) {
    vector<bool> is_prime(n + 1, true);
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i * i <= n; i++) {
        if (is_prime[i]) {
            for (int j = i * i; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }
    vector<int> primes;
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            primes.push_back(i);
        }
    }
    return primes;
}

int main() {
    int n;
    cout << "Enter the upper limit: ";
    cin >> n;
    vector<int> primes = sieveOfEratosthenes(n);
    cout << "Prime numbers up to " << n << " are:" << endl;
    for (int prime : primes) {
        cout << prime << " ";
    }
    cout << endl;
    return 0;
}

3. 计算一定范围内的素数个数

3.1 方法1:使用埃拉托斯特尼筛法
  • 步骤

    1. 使用埃拉托斯特尼筛法生成所有素数。

    2. 计算素数的个数。

  • 代码示例

#include <iostream>
#include <vector>
using namespace std;

int countPrimes(int n) {
    vector<bool> is_prime(n + 1, true);
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i * i <= n; i++) {
        if (is_prime[i]) {
            for (int j = i * i; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }
    int count = 0;
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            count++;
        }
    }
    return count;
}

int main() {
    int n;
    cout << "Enter the upper limit: ";
    cin >> n;
    cout << "Number of prime numbers up to " << n << " is: " << countPrimes(n) << endl;
    return 0;
}

4. 分解质因数

4.1 方法1:试除法
  • 步骤

    1. 从2开始,逐步尝试除以 n。

    2. 如果能整除,记录该质因数,并将 n 除以该质因数。

    3. 重复上述步骤,直到 n 为1。

  • 代码示例

#include <iostream>
#include <vector>
using namespace std;

vector<pair<int, int>> primeFactors(int n) {
    vector<pair<int, int>> factors;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            int count = 0;
            while (n % i == 0) {
                n /= i;
                count++;
            }
            factors.push_back({i, count});
        }
    }
    if (n > 1) {
        factors.push_back({n, 1});
    }
    return factors;
}

int main() {
    int n;
    cout << "Enter a number: ";
    cin >> n;
    vector<pair<int, int>> factors = primeFactors(n);
    cout << "Prime factors of " << n << " are:" << endl;
    for (const auto& factor : factors) {
        cout << factor.first << "^" << factor.second << " ";
    }
    cout << endl;
    return 0;
}

5. 计算欧拉函数

5.1 方法1:使用质因数分解
  • 步骤

    1. 分解 n 的质因数。

    2. 使用欧拉函数公式计算 ϕ(n)。

  • 代码示例

#include <iostream>
#include <vector>
using namespace std;

int eulerPhi(int n) {
    vector<pair<int, int>> factors = primeFactors(n);
    double result = n;
    for (const auto& factor : factors) {
        result *= (1.0 - (1.0 / factor.first));
    }
    return static_cast<int>(result);
}

int main() {
    int n;
    cout << "Enter a number: ";
    cin >> n;
    cout << "Euler's Totient Function of " << n << " is: " << eulerPhi(n) << endl;
    return 0;
}

6. 计算最大公约数(GCD)

6.1 方法1:欧几里得算法
  • 步骤

    1. 使用欧几里得算法递归计算最大公约数。

  • 代码示例

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int main() {
    int a, b;
    cout << "Enter two numbers: ";
    cin >> a >> b;
    cout << "GCD of " << a << " and " << b << " is: " << gcd(a, b) << endl;
    return 0;
}

7. 计算最小公倍数(LCM)

7.1 方法1:使用GCD
  • 步骤

    1. 使用GCD计算LCM。

  • 代码示例

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int lcm(int a, int b) {
    return a / gcd(a, b) * b;
}

int main() {
    int a, b;
    cout << "Enter two numbers: ";
    cin >> a >> b;
    cout << "LCM of " << a << " and " << b << " is: " << lcm(a, b) << endl;
    return 0;
}

总结

  • 判断素数:使用暴力法或优化的试除法。

  • 生成素数:使用埃拉托斯特尼筛法。

  • 计算素数个数:使用埃拉托斯特尼筛法。

  • 分解质因数:使用试除法。

  • 计算欧拉函数:使用质因数分解。

  • 计算最大公约数:使用欧几里得算法。

  • 计算最小公倍数:使用GCD。

这些方法在处理素数相关问题时非常有效。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值