给定范围的素数筛选(POJ 2689)
问题:求L 到 R范围内的所有素数 (L < R <= 2147483647, R - L <= 10^6)
解:要判断x是否是素数,可以看 x %(所有比x小的素数)是否有0出现。。。
当然,还可以优化一下 x % (所有比sqrt(x)小的素数)
已知 sqrt(2147483647) = 49361;
打出 [2, 49361]范围内的素数表,大约不到5000个素数。
然后用小于 sqrt(R)的素数乘上一个系数进行枚举,这样乘出来的数必然不是素数。把所有这些数筛小,剩下的就是素数了。
至于这个系数怎么确定?可以知道这个系数的下限为 K = L/prime[i],当然,如果prime[i] >= L的话,K初始为2。其实就是K*prime[i]要保证大于L且离L最近
打表:
CL(vis, true); for(LL i = 2; i < N; ++i) { for(LL j = LL(i)*LL(i); j < N; j += i) vis[j] = false; } n = 0; for(LL i = 2; i < N; ++i) { if(vis[i]) { prime[n++] = i; } }
筛掉非素数:
void get_p2(LL l, LL r) { LL i; LL k; if(r < N) { //如果r <= 49361,直接用原来的素数表就可以 i = 0; while(prime[i] < l) ++i; for(n2 = 0; prime[i] <= r; ++i) p2[n2++] = prime[i]; return ; } CL(vis, true); for(i = 0; i < n && prime[i]*prime[i] <= r; ++i) { if(prime[i] >= l) k = 2; else { k = l/prime[i]; if(k*prime[i] < l) ++k; } while(k*prime[i] <= r) { vis[k*prime[i] - l] = false; //printf("%lld %lld %d\n", k*prime[i], k*prime[i] - l, prime[i]); ++k; } } n2 = 0; for(i = 0; i <= r - l; ++i) { if(vis[i]) p2[n2++] = i + l; } }
设原素数表有n个素数,k增长次数的平均数为ave(k),时间复杂度为O(n*ave(k));