回想起来当时请教出了“野筛法”800ms+飘过这道题的时候,内心愧疚不已。后来的后来,我问到了更强的方法,线性筛选。复杂度O(n),当然了,容斥原理是最快的,但是我死活理解不了啊……
所谓线性筛选,就是我的条件很苛刻,对于每个合数,我只允许它被最小的素因子筛选。只筛一次,那就是线性啦!
if(i % prime[j] == 0) break;
枚举当前数,倘若它没有合数标记,送入素数表当中。之后开始用素数表筛它的倍数。一直筛到最小素因子(除得尽)为止。
vis[i * prime[j]] = 1;
模板如下:
const int MAXN = 10000001;
bool vis[MAXN];
int prime[700000];
void shai(){
int cnt = 0;
for(int i = 2; i < MAXN; i++) {
if(!vis[i]) prime[cnt++] = i;
for(int j = 0; j < cnt && prime[j]*i < MAXN; j++) {
vis[prime[j]*i] = 1;
if(i % prime[j] == 0) break;
}
}
}
代码如下:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define MAXN 10000001
bool vis[MAXN];
int prime[664580];
void shai(){
int c = 0;
for(int i = 2; i < MAXN; i++) {
if(!vis[i]) {
prime[c++] = i;
}
for(int j = 0; j < c && prime[j]*i < MAXN;j++) {
vis[prime[j]*i] = 1;
if(i % prime[j] == 0) break;
}
}
}
int main(){
int n;
shai();
vis[1] = 1;
while(scanf("%d", &n), n){
int s = 0;
for(int i = 1; i <= n; i++)
if(!vis[i]) s++;
printf("%d\n",s);
}
return 0;
}