质数

质数的定义

质数又称作素数.
质数是除了1和本身没有其他因数的数.
与之相反的是合数.
1不属于质数或合数.

质数的判断

假设我们要判断(n)是不是质数.
从2枚举(n-1),若能整除(n),(n)就不是质数.
时间复杂度(O(n)).
但因数是成对的(除了(sqrt n))
(n=c_1 c_2),假设(c_1 le c_2)
(c_1 le sqrt n , c_2 ge sqrt n)
所以只需枚举到(sqrt n).

bool isprime(long long x) {
    for(int i=2; i<=sqrt(x); i++) {
        if(x%i==0) return false;
    }
    return true;
}

时间复杂度(O(sqrt n)).

质数筛法

现在我们要求(1)(n)中全部质数.

暴力

最简单的办法就是判断每个数是否为质数.
时间复杂度(O(n sqrt n)).

埃氏筛法

(1)(sqrt n),若这个数没有被标记,即为质数.
只要发现了一个质数(t),就把从(1)(n)中全部(t)的倍数标记.
时间复杂度(O(n log n))

欧拉线性筛法

对于每个(i(1<i<n)),筛去所有小于(i)的质数与(i)的乘积.
不难发现,有些合数被重复筛去.
设所有小于(i)的质数分别为(p_1,p_2,...,p_j).
(i\%p_k=0)时,停止筛(i)的倍数,即可避免重复.
因为当(l>k)时,所有(i*p_l)都会被比(i)大的数与(p_k)的乘积筛去.

for(int i=2;i<=n;i++){
    if(!vis[i]) {
        cnt++;
        pri[cnt]=i;
    }
    for(int j=1;i*pri[j]<=n;j++){
        vis[i*pri[j]]=true;
        if(i%pri[j]==0) break;
    }
}

时间复杂度(O(n))

质因数分解

一个数的质因数必定小于等于(sqrt n).
只需把(i)(2)枚举到(sqrt n),从(n)中去掉所有(i)并做记录,就能求出(n)的质因数.

for(int i=2;i<=sqrt(n);i++) {
    while(n%i==0) {
        n/=i;
        cnt[i]++;
    }
}

时间复杂度(O(sqrt n))

欧拉函数

欧拉函数是从(1)(n-1)的数中与(n)互质的数的个数.
(φ(1)=φ(2)=1).

性质

  1. 对于质数(n),(φ(n)=n-1).
  2. 对于质数(p),(φ(p^k)=(p-1)*p^{k-1}).
  3. 对于互质的(n,m),(φ(n)*φ(m)=φ(n*m)).
  4. 对于奇数(n),(φ(2*n)=φ(n)).
  5. 对于(n(n>1)),(sum_{k=1}^n{k(gcd(n,k)=1)}=φ(n)*n/2).
  6. (k\%p=0),(φ(k*p)=φ(k)*p).
  7. (k\%p!=0),(φ(k*p)=φ(k)*(p-1)).
  8. 对于互质的(a,m),(a^{φ(p)} equiv 1 pmod {p}).
  9. (sum_{kmid n}^n{φ(k)}=n)
  10. (φ(n)=sum_{kmid n}^n{φ(k)*frac{n}{k}}).

计算公式及证明

(n)的质因数分解为(p_1^{c_1}*p_2^{c_2}*)...(*p_i^{c_i}).
(φ(n)=n*frac{p_1-1}{p_1}*frac{p_2-1}{p_2}*)...(*frac{p_i-1}{p_i})
证明:设(p,q)(n)的质因子.
(1)-(n)中,(p)的倍数有(frac{n}{p})个,(q)的倍数有(frac{n}{q})个,(p*q)的倍数有(frac{n}{p+q})个.
所以(1)(n-1)中与(p,q)互质的数的个数为
(egin{align*} n-frac{n}{p}-frac{n}{q}+frac{n}{p*q}&=n*(1-frac{1}{p}-frac{1}{q}+frac{1}{p*q})\ &=n*(1-frac{1}{p})*(1-frac{1}{q}) end{align*})
其他质因子同理.

算法实现

对于求单个欧拉函数,分解质因数即可.

for(long long i=2;i<=sqrt(num);i++) {
    bool div=false;
    while(num%i==0) {
        div=true;
        num/=i;
    }
    if(div) ans=ans*(i-1)/i;
}
if(num>1) ans=ans*(num-1)/num;

时间复杂度与质因数分解一样.
但如果要求从(1)(n)的数的欧拉函数,就可以通过打表法来求解.

for(int i=2;i<=MAXN;i++) {
    if(!phi[i]) {
        for(int j=i;j<=MAXN;j+=i) {
            if(!phi[j]) phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
    }
}

或是在欧拉筛时同时求出欧拉函数.

for(int i=2;i<=n;i++){
    if(!vis[i]) {
        cnt++;
        pri[cnt]=i;
        phi[cnt]=i-1;
    }
    for(int j=1;i*pri[j]<=n;j++){
        vis[i*pri[j]]=true;
        if(i%pri[j]==0) {
            phi[i*pri[j]]=phi[i]*pri[j];
            break;
        }
        phi[i*pri[j]]=phi[i]*(pri[j]-1);
    }
}
不忘初心 砥砺前行
原文地址:https://www.cnblogs.com/gzezfisher/p/prime.html