目录
质数的朴素筛法
根据定义,我们不难得出,如果要知道 \(1\)~\(n\) 范围内的所有质数,我们只需要从 \(2\) 到 \(n\) 开始枚举,再判断是否是质数即可:
bool isprime[MAXN];
for(int i=2;i<=n;i++){
isprime[i]=1;
for(int j=2;j*j<=i;j++){
if(i%j==0){
isprime[i]=0;
break;
}
}
}
当枚举到的数为 \(n\) 的时候,内层的复杂度是 \(O(\sqrt n)\) 的,而外层 \(O(n)\) 枚举
因此,很多人觉得是 \(O(n\sqrt n)\) 的
其实,本人对此持怀疑态度:本人认为只有 \(o(n\sqrt n)\)
首先:每个合数都是被自己的最小质因子筛到,而每个质数 \(p\) 花费的时间是 \(O(\sqrt p)\)
质数的很显然,对于合数的,我们用反证法:如果这个数 \(m\) 的最小质因数为 \(fc\) ,它被判定为合数时 \(i=k\)
因此, \(m\) 应该在 \(k\) 之前都不能退出循环
而如果 \(fc\) 为 \(k\) 的因数,\(fc<k\)(因为 \(k\) 为合数);如果不为的话, \(k\) 的最小质因数假设为 \(fc'\) 则 \(fc<fc'<k\)
因此, \(m\) 在 \(fc\) 时就一定退出了
综上,复杂度其实并没有达到 \(O(n\sqrt n)\) ,其实复杂度是更小的
优化
我们考虑每个合数,一定是被它的最小质因数筛到。而一个数 \(n\) 的最小质因数 \(fc\) ,一定有 \(fc\in Prime,fc\leq n\)
所以,我们把之前筛到的所有质数存起来,依次判断是不是这个数的因数就行了
bool isprime[MAXN];
int prime[MAXN]={2},cntprime=1;
for(int i=3;i<=n;i++){
isprime[i]=1;
for(int j=1;prime[j]*prime[j]<=i;j++){
if(i%prime[j]==0){
isprime[i]=0;
break;
}
}
if(isprime[i]==1){
prime[cntprime++]=i;
}
}
因为 \(1\)~\(n\) 的质数个数约等于 \(n\over\ln n\) (我们假定特殊化处理:\(\ln 1=1\))
所以复杂度为 \(\displaystyle T(n)=\sum_{i=1}^n {\sqrt{i}\over \ln \sqrt{i}}=2\sum_{i=1}^n{\sqrt{i}\over \ln i}\)
可以证明,复杂度 \(T(n)\) 与变上限函数 \(\displaystyle \int_a^n {\sqrt{i}\over\ln i}\text di\) 是同阶的
不过很可惜,这玩意儿的积分我不会,不过我们可以发现:当 \(n\) 足够大时,一定会满足下面不等式:
\({\text d\over \text di}(i\ln\ln i)=\ln\ln i+{1\over \ln i}\leq {\sqrt i\over \ln i}\leq \ln i+1= {\text d\over \text di}(i\ln i)\leq {3\over 2}\sqrt i={\text d\over \text di}(i\sqrt i)\)
因此 \(\displaystyle n\ln\ln n\leq \int_a^n{\sqrt i\over \ln i}\text di\leq n\ln n\leq n\sqrt n\)
所以,我们可以说,这个方法肯定是更优的,复杂度是 \(o(n\log n)\) 的,但因为同时也是 \(\omega(n\log\log n)\)