素数
求从1...n的素数: 埃氏筛, 快速线性筛.
埃氏筛
// 1e8 // 2 * i 2859 // 1ll * i * i 1980 bool prime[maxn];int get(int size) { int cnt = 0; for (int i=0; i<size; ++i) prime[i] = true; prime[0] = prime[1] = false; for (int i=2; i<size; ++i) { if (prime[i]) { cnt++; for (long long k=1ll*i*i; k<size; k+=i) { // 1ll * i * i 注意要用 long long 因为int容易爆. prime[k] = false; } } } return cnt; }
快速线性筛:(近似线性)
// 1e8 1232 int prime[maxn]; int isNotPrime[maxn]; int get(int size) { int cnt = 0; isNotPrime[0] = isNotPrime[1] = 1; for (int i=2; i<size; ++i) { if (!isNotPrime[i]) prime[cnt++] = i; for (int j=0; j<cnt && i*prime[j]<size; j++) { isNotPrime[i * prime[j]] = 1; if (! (i % prime[j])) break; } } return cnt; }
// 取某一段大区间的素数 区间长度1e6左右的. // 先预处理2...sqrt(最大数)之间的素数表. // 然后 把数移动到[left, right]上,然后筛. bool isprime[maxn]; void get2(int left, int right, int old_cnt) { // 求[left, right] 区间的素数 old_cnt是素数表的素数(先预处理的素数表 [2..Sqrt(Max_Value)]的素数表). int i, j; if (left == 1) left++; // 素数筛 for (i=0; i<maxn; ++i) isprime[i] = true; for (i=0; i < old_cnt; ++i) { if (prime[i] > right) break; for (ll j= 1ll * (left / prime[i]) * prime[i]; j<=right; j+=prime[i]) { // 注意 long long 不然可能会爆. if (j < 1ll*left || j==1ll*prime[i]) continue; isprime[right - j] = false; } } int len = right - left; for (i=len; i>=0; --i) { if (isprime[i]) { // 对应素数是 right - i } } }