素数对
思路
拿到这道题,我们要找满足 的素数三元组
,其中
都是素数且都不超过
。注意
的顺序不同算不同的三元组。
首先想一个关键的约束:因为 ,
,所以
,也就是
,即
。当
时,
最大也就到
左右。这意味着我们需要枚举的
的范围非常小!
有了这个观察,算法就很直接了:
- 筛素数:用埃氏筛预处理出
中所有素数。
- 枚举 C:对每个素数
,计算
。
- 枚举 A:
的范围是
,因为
必须满足
。对范围内的每个素数
,检查
是否也是素数,是就计数加一。
由于 的范围很小(不超过
),每个
对应的枚举范围也不超过
,总体计算量是可以接受的。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d", &n);
vector<bool> sieve(n+1, true);
if(n >= 0) sieve[0] = false;
if(n >= 1) sieve[1] = false;
for(int i = 2; (long long)i * i <= n; i++){
if(sieve[i]){
for(int j = i*i; j <= n; j += i)
sieve[j] = false;
}
}
long long ans = 0;
int clim = (int)sqrt(2.0 * n) + 1;
for(int c = 2; c <= min(clim, n); c++){
if(!sieve[c]) continue;
long long csq = (long long)c * c;
if(csq < 4) continue;
int lo = (int)max(2LL, csq - n);
int hi = (int)min((long long)n, csq - 2);
if(lo > hi) continue;
for(int a = lo; a <= hi; a++){
if(!sieve[a]) continue;
int b = (int)(csq - a);
if(sieve[b]) ans++;
}
}
printf("%lld\n", ans);
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
boolean[] sieve = new boolean[n + 1];
java.util.Arrays.fill(sieve, true);
if (n >= 0) sieve[0] = false;
if (n >= 1) sieve[1] = false;
for (int i = 2; (long) i * i <= n; i++) {
if (sieve[i]) {
for (int j = i * i; j <= n; j += i)
sieve[j] = false;
}
}
long ans = 0;
int clim = (int) Math.sqrt(2.0 * n) + 1;
for (int c = 2; c <= Math.min(clim, n); c++) {
if (!sieve[c]) continue;
long csq = (long) c * c;
if (csq < 4) continue;
int lo = (int) Math.max(2, csq - n);
int hi = (int) Math.min(n, csq - 2);
if (lo > hi) continue;
for (int a = lo; a <= hi; a++) {
if (!sieve[a]) continue;
int b = (int) (csq - a);
if (sieve[b]) ans++;
}
}
System.out.println(ans);
}
}
import sys, math
def main():
n = int(sys.stdin.read())
if n < 2:
print(0)
return
sieve = [True] * (n + 1)
sieve[0] = sieve[1] = False
for i in range(2, int(n**0.5) + 1):
if sieve[i]:
for j in range(i*i, n+1, i):
sieve[j] = False
ans = 0
clim = int(math.sqrt(2.0 * n)) + 1
for c in range(2, min(clim, n) + 1):
if not sieve[c]:
continue
csq = c * c
if csq < 4:
continue
lo = max(2, csq - n)
hi = min(n, csq - 2)
if lo > hi:
continue
for a in range(lo, hi + 1):
if not sieve[a]:
continue
b = csq - a
if sieve[b]:
ans += 1
print(ans)
main()
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
rl.on('line', (line) => {
const n = parseInt(line.trim());
if (n < 2) {
console.log(0);
return;
}
const sieve = new Uint8Array(n + 1).fill(1);
sieve[0] = 0;
sieve[1] = 0;
for (let i = 2; i * i <= n; i++) {
if (sieve[i]) {
for (let j = i * i; j <= n; j += i)
sieve[j] = 0;
}
}
let ans = 0;
const clim = Math.floor(Math.sqrt(2.0 * n)) + 1;
for (let c = 2; c <= Math.min(clim, n); c++) {
if (!sieve[c]) continue;
const csq = c * c;
if (csq < 4) continue;
const lo = Math.max(2, csq - n);
const hi = Math.min(n, csq - 2);
if (lo > hi) continue;
for (let a = lo; a <= hi; a++) {
if (!sieve[a]) continue;
const b = csq - a;
if (sieve[b]) ans++;
}
}
console.log(ans);
});
复杂度分析
- 时间复杂度:
。筛素数是
。枚举部分,
最大到
,对每个
枚举的范围不超过
,所有素数
的
之和远小于
,因此枚举部分总计也是
级别。
- 空间复杂度:
,用于存储素数筛数组。

京公网安备 11010502036488号