线性筛-prime,强大O(n)
和朴素的素数筛法一样,flag数组,记录x是否为素数
flag[x]=0,x为合数
falg[x]=1,x为素数
flag[1],无定义
其核心思想是,用x筛除与之差异最小的y,达到时间上O(n)的目的
何为差异最小,呢?
基于唯一分解定理,我们认为,x的素数分解集合(是可重集)
大小记为|x|,如果|x|+1=|y|,我们则认为x,y差异最小
即此时用x筛去y
更重要的一点:
if(i%p[j]==0)break;
什么意思呢?
可以这样理解,此时的break是为了下一次筛(暂时的失败是为了下一次更好的成功)
应为,能被i筛去的,一定能被p[j]筛去,p[j]后面的下一次反正会用到
所以让p[j]和它后面的素数去筛就好了
举一个栗子:
用2,3我们可以筛去4,6,9
像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
a[0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 ]
但是
4,只会筛去8,而没有12
因为,12是留给6筛的,所以代码就很简单了
1 typedef long long ll; 2 const int MAXP=50000+10; 3 ll p[MAXP],flag[MAXP],cnt; 4 void prime(int n){ 5 for(int i=2;i<=n;i++){ 6 if(!flag[i])p[++cnt]=i; 7 for(int j=1;j<=cnt && i*p[j]<=n;j++){ 8 flag[i*p[j]]=1; 9 if(i%p[j]==0)break; 10 } 11 } 12 } 13 int main(){ 14 prime(100); 15 for(int i=1;i<=cnt;i++)printf("p[%d]=%lld\n",i,p[i]); 16 return 0; 17 }
~~Jason_liu O(∩_∩)O