集训的确很有助于提升实力,蒟蒻的我也有不小的收获233
在做一道 '积性函数' 的题的时候用到了它
(虽然打完表当时我就看不懂题了,之后经过讲解才明白那是个递归思想来的递归推导式)
- 欧拉筛的原理是,将一个自然数分解为其最小质因子与一个合数(或者质数的乘积)
- 参考 '质数唯一分解定理' ,不了解请自行百度
(也就是我们其实还可以将这个合数再次分解为其他质因数的k次方的连乘 ) - 能力尚且有限,详细写在注释里了,可供一样在学的朋友参考
-code-
#include <iostream>
using namespace std;
typedef long long ll;
void faster_read() {
ios::sync_with_stdio(false);
//cin.tie(0); //同步输入输出,也就是输入完了才输出;
//cout.tie(0); //特殊情况下会拖慢很多时间;
}
ll primes[1000001];
bool p_mark[1000001]; //bool类型或char类型占一字节(char类型不代表必须是字符,我们只是用它的值)
ll eluer_prime(ll maxNum)
{
ll p_cnt=0;
for (int i = 2; i < maxNum; ++i) {
if (!p_mark[i]) primes[p_cnt++]=i;
for (int j = 0; (primes[j]<i*maxNum) && (j<p_cnt) ; ++j){
p_mark[i* primes[j]]=true;
if (i% primes[j]==0) break;
}
}
return p_cnt;
}
//三个内层循环结束条件:
//1. [i*primes[j]<maxNum(看需求可以换成'<='), 防止越界,这里不要用除法,用除法因为向下取整会导致筛除出错] ;
//2. [j<p_cnt, p_cnt是动态更新的质数表长度,此语句防止素数表越界] ;
//3. [i%primes[j]!=0,最关键的一步,当前的i可被当下primes[j]整除,此时需要停止标记,否则会有重复筛除] ;
// 例如i=8,素数序列为2,3,5,7,primes[j]==2时i/primes[j]==0,应当停止,如果继续,下一个筛除的数是3*8=24,但24应该由12筛除 ;
// 按照原理,它应该是一个最小质因数与一个合数(质数)的乘积这种唯一分解,对于24,其最小质因子应是2;
// 类推得到,如果在这时候不停止筛除,接下来筛除的数被大于其最小质因子的prime[j+1]筛除一次,而i到其分解的非最小质因子部分时就会对该数进行额外筛除,拖慢效率;
// 而prime[j+1]不是筛除数的最小质因子,也不再满足原理了 ;
int main()
{
faster_read();
ll pn=eluer_prime(30);
cout<<pn<<'\n';
for (int i = 0; i < pn; ++i) {
cout<<primes[i]<<' ';
}
}
*注意需要的数据是否会爆了某个表达式,如果会爆那么就转化成long long来运算,同时注意其他数据类型会不会导致溢出或丢失精度。
*修改了一下之前的错误,终止条件不能写成primes[j]=maxNum/i,这么写会导致判断出错,筛除出现纰漏!