判定质数


①试除法
②埃氏筛、线性筛

//线性筛打质数表
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int prime[N],vis[N],cnt;

void get_prime(int x){
    for(int i=2;i<=x;i++){
        if(!vis[i])
            prime[++cnt] = i;
        for(int j=1;prime[j]<=x/i;j++){
            vis[i*prime[j]] = 1;
            if(i%prime[j] == 0)
                break;
        }
    }
}
int main(){
    int n;
    cin>>n;
    get_prime(n);
    for(int i=1;i<=cnt;i++)
        cout<<prime[i]<<' ';
}

③巨大质数的判断
判断n是否为质数时,枚举多个质数a,对于每个枚举的a,满足gcd(n,a) = 1且,有一个a不满足则n不是质数


分解质因数


//分解质因数
#include<bits/stdc++.h>
using namespace std;
map<int,int> M;

void calc(int x){
    for(int i=2;i<=x/i;i++){
        while(x%i == 0){
            M[i]++;
            x/=i;
        }
    }
    if(x > 1)   //x中最多有一个大于根号x的质因子
        M[x]++;
}
int main(){
    int n;
    cin>>n;
    calc(n);
    for(auto k:M)
        cout<<k.first<<' '<<k.second<<endl;
}

暴力求约数:只筛质因子+dfs爆搜

试除法求所有约数


//求一个数所有的约数
#include<bits/stdc++.h>
using namespace std;
set<int> S;

void calc(int x){
    for(int i=1;i<=x/i;i++)
        if(x%i == 0){
            S.insert(i);
            S.insert(x/i);
        }
}
int main(){
    int n;
    cin>>n;
    calc(n);
    for(auto k:S)
        cout<<k<<endl;
}

唯一分解定理



P1、P2、......Pn为N的质因子

n的约数个数:

n的约数之和:

求1~n所有数的约数个数和:

①1的倍数有N/1个(同理1是N/1个数的约数)
②2的倍数有N/2个
③N的倍数有N/N个

整除分块(数论分块):

以n==8为例:
图片说明
求1~N所有数的约数个数和或者所有数的约数和不需要逐个计算,可以分块计算,最多可分为个块(不做证明,可查资料),一个块的r=n/(n/l)


扩展欧几里得算法


int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x = 1;
        y = 0;
        return a;
    }
    int d = exgcd(b,a%b,y,x);
    y -= a/b*x
}

有整数解的条件:c%gcd(a,b) == 0

解出来的x1、y1为ax+by = gcd(a,b)的特解
ax+by=c的特解为x1*c/gcd(a,b)、y1*c/gcd(a,b)

通解:x=x1+b/d*t , y=y1-a/d*t(t为任意整数)


欧拉函数:1~n中与n互质的数的个数称为欧拉函数,记作


根据唯一分解定理:

分解质因数过程中求欧拉函数:

//公式法求欧拉函数
#include<bits/stdc++.h>
using namespace std;
int calc(int x){
    int cnt=x;
    for(int i=2;i<=x/i;i++){
        if(x%i == 0)
            cnt = cnt/i*(i-1);
        while(x%i == 0)
            x /= i;
    }
    if(x > 1)
        cnt = cnt/x*(x-1);
    return cnt;
}
int main(){
    int n;
    cin>>n;
    cout<<calc(n)<<endl;;
}

筛法求欧拉函数:

#include<bits/stdc++.h>
using namespace std;
int phi[100],vis[100],prime[100];

void calc(int x){
    phi[1] = 1;
    int cnt=0;
    for(int i=2;i<=x;i++){
        if(!vis[i]){
            prime[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;prime[j]<=x/i;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j] == 0){
                phi[i*prime[j]] = phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]] = phi[i]*(prime[j]-1);
        }
    }
}
int main(){
    int n;
    cin>>n;
    calc(n);
    for(int i=1;i<=n;i++)
        cout<<phi[i]<<endl;
}