素数线性筛与因子个数

这个是将所有素数按大小顺序排列在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;


}

发布了9 篇原创文章 · 获赞 9 · 访问量 6565

猜你喜欢

转载自blog.csdn.net/qq_43413369/article/details/103614538