素数
素数:一个数 n ,若不能在[2,n-1]中找到一个能整除 n 的数 d ,则 n 为素数。
试除法判断素数
时间复杂度:
bool is_prime(int n) {
if (n <= 1) return false;
for(int i = 2; i * i <= n; ++ i) {
if (n % i == 0) return false;
}
return true;
}埃氏筛法
时间复杂度:
原理:每次筛出一个素数 x,并把 x 的倍数筛出。
注:对于 [ 2 * i,i * i ] 之间的合数会被比 i 更小的素数筛去,所以 j = i * i, 但要防止爆int。
const int maxn = 1e7+1;
const int maxm = 664579 + 1;
bool vis[maxn];
int prime[maxm]; // 1~1e7 中素数个数为 664579
void E_sieve(int n) { // 埃氏筛
int tot = 0;
for(int i = 1; i <= n; ++ i) vis[i] = 0;
for(long long i = 2; i <= n; ++ i) {
if (vis[i]) continue;
prime[++tot] = i;
for(long long j = i * i; j <= n; j += i) {
vis[j] = 1;
}
}
return tot;
}欧拉筛(线性筛)
时间复杂度:
原理:每个合数都是由它的最小质因子筛去。
注: if (i % prime[j] == 0) break; 保证了一个数不会被重复筛去。
const int maxn = 1e8+1;
const int maxm = 5761455 + 1;
bool vis[maxn];
int prime[maxm]; // 1~1e8 之间素数个数为 5761455
int E_sieve(int n) { // 欧拉筛
int tot = 0;
for(int i = 1; i <= n; ++ i) vis[i] = 0;
for(long long i = 2; i <= n; ++ i) {
if (!vis[i]) prime[++tot] = i;
for(int j = 1; i * prime[j] <= n; ++ j) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
return tot;
}区间筛
const int maxn = 1e6+1;
bool vis[maxn];
int prime[maxn];
int E_sieve(int n) { // 线性筛
int tot = 0;
for(int i = 1; i <= n; ++ i) vis[i] = 0;
for(long long i = 2; i <= n; ++ i) {
if (!vis[i]) prime[++tot] = i;
for(int j = 1; i * prime[j] <= n; ++ j) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
return tot;
}
int S_sieve(long long l, long long r) { // 区间筛(埃氏筛)
int tot = E_sieve(sqrt(r));
for(long long i = l; i <= r; ++ i) vis[i-l+1] = 0;
for(int i = 1; i <= tot; ++ i) { // 用2~sqrt(r)素数筛去l~r之间的素数
long long t = prime[i];
if (t * t > r) break;
long long j = max((l+t-1)/t*t, 2*t); // 素数本身不能被筛
for(; j <= r; j += t) vis[j-l+1] = 1;
}
int res = 0;
for(long long i = max(l,2ll); i <= r; ++ i) // 1 不是素数
if (!vis[i-l+1]) res ++;
return res;
}数学 文章被收录于专栏
关于acm竞赛数论的个人笔记

