看到的好版本
https://www.cnblogs.com/-citywall123/p/10066464.html
tips:欧拉筛代码得到指数的同时,还得到每个数对应的欧拉函数。
https://blog.csdn.net/codertcm/article/details/82837259
算法简述
我们希望找到 1 - N内所有的质数。做法时标记每一个数,质数标记为0,合数标记为1。初始化每个数都是0。现在从小到大对每个数依次排查。对每个数 n n n 有两步操作:
- 如果标记为0,加入到质数数组。
- 无论 n 是不是质数,都将 n 和质数数组里的每一个数依次相乘。注意是依次。核心来了:如果相乘时发现 n 是该质数的倍数,先将它们的积标记为1,再终止第二步。
第二步里标记和终止的顺序不能交换,一定先标记,再交换。不然会有一些合数该被标记却没被标记为1. 终止的做法可以减少一个合数被重复标记的次数。
证明
证明: 任一一个合数 n 都会被标记为1
合数 n 可以写成 n = m 1 ∗ m 2 , m 1 < = m 2 n = m_1 * m_2,m_1 <= m_2 n=m1∗m2,m1<=m2.
- m 1 , m 2 m_1, m_2 m1,m2 都是质数,则当程序运行到 m 2 m_2 m2 轮次时, n 被标记为1。
- m 1 m_1 m1 是质数, m 2 m_2 m2 是合数。可以证明对于任一合数我们总能找到一组 m 1 , m 2 , 其 中 m 1 是 质 数 , m 2 是 合 数 , 且 m 1 < m 2 m_1, m_2, 其中 m_1是质数, m_2是合数,且 m_1 < m_2 m1,m2,其中m1是质数,m2是合数,且m1<m2. 因为任一合数等于一些质数相乘,令 m 1 m_1 m1 为最小的质数, m 2 m_2 m2 为其他质数的积。则程序运行到 m 2 m_2 m2 轮次 时, n 被标记为1.
tips:每一个数可能不止被标记一次,例如 n = 3 ∗ 5 ∗ 7 ∗ 11 n = 3 * 5 * 7 * 11 n=3∗5∗7∗11, 轮次 3 ∗ 5 ∗ 7 3*5*7 3∗5∗7, 3 ∗ 5 ∗ 11 3*5*11 3∗5∗11,时都会被标记。
代码
#include <iostream>
#include <vector>
using namespace std;
void EulerPrime(int n){
if(n == 1){
cout << 0;
return;
}
int flag[n+1] = {};
int prime[n+1];
int count = 0;
for(int i = 2; i <= n; i++){
if(flag[i] == 0) prime[++count] = i;
for(int j = 1; j <= count && i*prime[j] <= n; j++){
flag[i*prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
for(int i = 1; i <= count; i++){
cout << prime[i] << endl;
}
cout << count << endl;
}
int main(){
int n;
cin >> n;
EulerPrime(n);
return 0;
}