质数
1、试除法判断质数
bool is_prime(int x) // 判定质数
{
if (x < 2) return false;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
return false;
return true;
}
/*
这里使用"i <= x / i"是防止"i*i"太大超过int范围,
注意要使用等于号"=",防止质数的平方这种数
*/
2、试除法分解质因数
由算数基本定理可得:对于每个大于1的正整数n,存在一组质数p1, p2, …, pk,以及对应的正整数指数e1, e2, …, ek,使得n = p1e1 * p2e2 * … * pkek。 同时,这种表示方式是唯一的,即如果存在另一组质数q1, q2, …, qm,以及对应的正整数指数f1, f2, …, fm,使得n = q1f1 * q2f2 * … * qmfm,那么这两组质数和指数必须完全相同。根据这一原理我们可以使用试除法分解质因数。
备注:循环里面的 i 一定是一个质数:假如 i 是一个合数,那么它一定可以分解成多个质因子相乘的形式,这多个质因子同时也是 a 的质因子且比 i 要小,而比 i 小的数在之前的循环过程中一定是被条件除完了的,所以 i 不可能是合数,只可能是质数.
void divide(int x)
{
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s ++ ;
cout << i << ' ' << s << endl;
}
if (x > 1) cout << x << ' ' << 1 << endl;
cout<<endl;
}
3、筛质数
(1)普通筛
int const N = 1e7;
int primes[N]{0};
bool st[N]{0};
int cnt=0;
void get_primes(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i]) primes[cnt++]=i;//把素数存起来
for(int j=i;j<=n;j+=i)//不管是合数还是质数,都用来筛掉后面它的倍数
{
st[j]=true;
}
}
}
(2)埃氏筛
int const N = 1e7;
int primes[N]{0};
bool st[N]{0};
int cnt=0;
void get_primes(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i])
{
primes[cnt++]=i;
for(int j=i;j<=n;j+=i) st[j]=true;//可以用质数就把所有的合数都筛掉;
}
}
}
(3)线性筛
int const N = 1e7;
int primes[N]{0};
bool st[N]{0};
int cnt=0;
void get_primes(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++) //只筛选比n小的合数
{
st[primes[j]*i]=true; //只用最小质因子去筛合数
if(i%primes[j]==0) break;
}
}
}
/*
当i%primes[j]!=0时,
说明此时遍历到的primes[j]不是i的质因子,
那么只可能是此时的primes[j]<i的最小质因子,
所以primes[j]*i的最小质因子就是primes[j];
当有i%primes[j]==0时,
primes[j]*i的最小质因子也就应该是prime[j]
之后接着用st[primes[j+1]*i]=true去筛合数时,
就不是用最小质因子去更新了,
因为i有最小
质因子primes[j]<primes[j+1],
此时的primes[j+1]不是primes[j+1]*i的最小质因子,
此时就应该退出循环
*/