这个是将所有素数按大小顺序排列在prime数组里,数组从prime[1]开始,prime[0]存储数组内所有素数个数
//先将prime[]所有值都设置为0,即素数
int prime[max + 5] = {0};
void init() {
//从2开始
for (int i = 2; i <= max; i++) {
//如果是素数,就将i值存入++prime[0]中,即按顺序存储素数
if (!prime[i]) prime[++prime[0]] = i;
//将j设置为相乘的素数,用prime[j]表示
for (int j = 1; j <= prime[0] && prime[j] * i <= max; j++) {
prime[prime[j] * i] = 1;
if (i % prime[j] == 0) break;
}
}
return ;
}
//prime[]数组为素数数组
基本思想
初始数组全为0, 即设置所有数都是素数,当确定数字不是素数时,标记为1
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
i = 2开始,prime[1]=2, 将2存入prime第1个数里,2 * 2 = 4,标记4
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
i = 3,prime[2] = 3, 存入3,并标记2 * 3 和 3 * 3
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
i = 4, 标记2 * 4,因为此时i % prime[1] = 0, 即4 % 2 = 0,标记一个即停止
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
i = 5, prime[3] = 5, 并标记 2 * 5, 3 * 5, 5 * 5
2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
以此类推,
最终prime[ 1 ~ i ] 为 2, 3, 5, 7, 11, 13…
下面这个是将prime数组的所有数标记为0和1,0为素数1为非素数
int prime[8000005] = {1, 1};
int main() {
int n;
cin >> n;
for (int i = 2; i * i <= n; i++) {
if (!prime[i]) {
for (int j = 2; i * j <= n; j++)
prime[i * j] = 1;
}
}
int sum = 0;
for (int i = 2; i * 2 <= n; i++) {
if (!prime[i] && !prime[n - i]) sum++;
}
cout << sum;
}
两段整合
int prime[N + 5] = {0};
int is_prime[N + 5] = {0};
void init() {
for (int i = 2; i <= N; i++) {
if (!is_prime[i]) prime[++prime[0]] = i;
for (int j = 1; j <= prime[0] && i * prime[j] <= N; j++) {
is_prime[prime[j] * i] = 1;
if (i % prime[j] == 0) break;
}
}
return ;
}
欧拉第47题
不同的质因数
首次出现连续两个数均有两个不同的质因数是在:
14 = 2 × 7
15 = 3 × 5
首次出现连续三个数均有三个不同的质因数是在:
644 = 22 × 7 × 23
645 = 3 × 5 × 43
646 = 2 × 17 × 19
首次出现连续四个数均有四个不同的质因数时,其中的第一个数是多少?
#include<iostream>
#include<vector>
#include<math.h>
#include<string>
#include<algorithm>
#include<iomanip>
using namespace std;
#define N 1000000
int prime[N + 5] = {0};
void init() {
for (int i = 2; i <= N; i++) {
if (prime[i]) continue;
for (int j = i; j <= N; j += i) {
prime[j] += 1;
}
}
return ;
}
int main() {
int ans = 0;
init();
for (int i = 1000; i <= N; i++) {
int flag = 1;
for (int j = 0; j < 4 && flag; j++) {
flag = (prime[i + j] == 4);
}
if (!flag) continue;
ans = i;
break;
}
cout << ans << endl;
}
欧拉第21题
亲和数
记d(n)为n的所有真因数(小于n且整除n的正整数)之和。
如果d(a) = b且d(b) = a,且a ≠ b,那么a和b构成一个亲和数对,a和b被称为亲和数。
例如,220的真因数包括1、2、4、5、10、11、20、22、44、55和110,因此d(220) = 284;而284的真因数包括1、2、4、71和142,因此d(284) = 220。
求所有小于10000的亲和数的和。
暴力解决方法
#include<iostream>
#include<vector>
#include<math.h>
#include<string>
#include<algorithm>
#include<iomanip>
using namespace std;
#define N 10000
int f[N + 5] = {0};
void init() {
for (int i = 1; i <= N; i++) {
for (int j = 2; i * j <= N; j++) {
f[i * j] += i;
}
}
return ;
}
int main() {
init();
long long sum = 0;
for (int i = 2; i < N; i++) {
if (f[i] != i && f[i] < N && i == f[f[i]])
sum += i;
}
cout << sum << endl;
return 0;
}
线性筛方法
#include<iostream>
#include<vector>
#include<math.h>
#include<string>
#include<algorithm>
#include<iomanip>
using namespace std;
#define N 4000000
int prime[N + 5] = {0};
int f[N + 5] = {0};
int cnt[N + 5] = {0};
void init() {
for (int i = 2; i <= N; i++) {
if (!prime[i]) {
prime[++prime[0]] = i;
f[i] = i + 1;
cnt[i] = 1;
}
for (int j = 1; j <= prime[0]; j++) {
if (prime[j] * i > N) break;
prime[prime[j] * i] = 1;
if (i % prime[j] == 0) {
f[i * prime[j]] = f[i] / (pow(prime[j], cnt[i] + 1) - 1) * (pow(prime[j], cnt[i] + 2) - 1);
cnt[i * prime[j]] = cnt[i] + 1;
break;
}else {
f[i * prime[j]] = f[i] * f[prime[j]];
cnt[i * prime[j]] = 1;
}
}
}
return ;
}
int main() {
long long sum = 0;
init();
for (int i = 2; i < N; i++) {
f[i] -= i;
}
for (int i = 2; i < N; i++) {
if (f[i] != i && f[i] < N && f[f[i]] == i)
sum += i;
}
cout << sum << endl;
}
方法2优化
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
#define max_n 4000000
int prime[max_n + 5] = {0};
ll f[max_n + 5] = {0};
ll cnt[max_n + 5] = {0};
void init() {
for (int i = 2; i <= max_n; i++) {
if (!prime[i]) {
prime[++prime[0]] = i;
f[i] = i + 1;
cnt[i] = i * i;
}
for (int j = 1; j <= prime[0]; j++) {
if(prime[j] * i > max_n) break;
prime[prime[j] * i] = 1;
if (i % prime[j] == 0) {
f[i * prime[j]] = f[i] * (cnt[i] * prime[j] - 1) / (cnt[i] - 1);
cnt[i * prime[j]] = cnt[i] * prime[j];
break;
}
else {
f[i * prime[j]] = f[i] * f[prime[j]];
cnt[i * prime[j]] = prime[j] * prime[j];
}
}
}
return ;
}
int main() {
init();
ll sum = 0;
for (int i = 2; i < max_n; i++) {
f[i] -= i;
}
for (int i = 2; i < max_n; i++) {
if(f[i] != i && f[i] < max_n && i == f[f[i]]) {
sum += i;
}
}
cout << sum << endl;
return 0;
}
高度可约的三角形数
三角形数数列是通过逐个加上自然数来生成的。例如,第7个三角形数是 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28。三角形数数列的前十项分别是:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, …
让我们列举出前七个三角形数的所有约数:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
我们可以看出,28是第一个拥有超过5个约数的三角形数。
第一个拥有超过500个约数的三角形数是多少?
#include<iostream>
#include<vector>
#include<math.h>
#include<string>
#include<algorithm>
#include<iomanip>
using namespace std;
#define N 1000000
int prime[N + 5] = {0};
int f[N + 5] = {0};
int cnt[N + 5] = {0};
void init() {
for (int i = 2; i <= N; i++) {
if (!prime[i]) {
prime[++prime[0]] = i;
f[i] = 2;
cnt[i] = 1;
}
for (int j = 1; j <= prime[0] && prime[j] * i <= N; j++) {
prime[prime[j] * i] = 1;
if (i % prime[j] == 0) {
f[i * prime[j]] = f[i] / (cnt[i] + 1) * (cnt[i] + 2);
cnt[i * prime[j]] = cnt[i] + 1;
break;
}else {
f[prime[j] * i] = f[prime[j]] * f[i];
cnt[prime[j] * i] = 1;
}
}
}
return ;
}
int main() {
init();
int n = 0, fac = 0;
while (fac < 500) {
n++;
if (n & 1) {
fac = f[n] * f[(n + 1) >> 1];
}else {
fac = f[n >> 1] * f[n + 1];
}
}
cout << n * (n + 1) / 2 << endl;
}