# 数论基础总结

数论基础总结

数论基础

整除

定义 若整数$b$除以非零整数$a$,商为整数,且余数为零, 就说$b$能被$a$整除(或说$a$能整除$b$)。

同余

若整数$a$和整数$b$除以正整数$m$的余数相等,则称$a,b$模$m$同余,记为$a \equiv b \pmod{m}$

整数唯一分解定理

任何一个大于1的自然数$N$,如果$N$不为素数,那么$N$可以唯一分解成有限个素数的乘积:

$N=P^{a_1}_1P^{a_2}_2......P^{a_n}_n$

$P_1 < P_2 <......< P_n$均为质数,指数$a_i$为正整数。这样的分解称为$N$的标准分解式

素数

素数概念:一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做素数;否则称为合数(相应的,1既不是素数也不是合数)

求素数的方法:

暴力求解

#include<bits/stdc++.h>
using namespace std;
bool Prime(int n){
    for(int i=2;i<n;i++){
        if(n%i==0)return false;
    }
    return true;
}
int main(){
    int n;
    cin>>n;
    if(Prime(n)){
        cout<<"Yes";
    }else{
        cout<<"No";
    }
}

很明显,时间复杂度$O(n)$,$n$一大就炸。

对暴力做一点点优化

由于如果有一个数$x$满足$x=a \times b$,那么$x$必然满足$x = b \times a$。

那这有什么用呢?借助这一性质可以对暴力做一点点优化:

#include<bits/stdc++.h>
using namespace std;
bool Prime(int n){
    for(int i=2;i*i<=n;i++){
        if(n%i==0)return false;
    }
    return true;
}
int main(){
    int n;
    cin>>n;
    if(Prime(n)){
        cout<<"Yes";
    }else{
        cout<<"No";
    }
}

就这样,时间复杂度$O(\sqrt n)$。

埃氏筛

但是如果检测多个数,还是太慢了,优化,必须大大滴优化。

借着质数的倍数是合数的理念,终于可以得到:

int p[N], v[N];
void Prime(int n) {
    int i, j; 
    for (i = 2; i <= n; i++) {
        if (v[i]) continue;
        p[++p[0]] = i;
        for (j = 2 * i; j <= n; j += i) v[j] = 1;
    }
}

时间复杂度$O(n\log \log n)$。

欧式筛(线性筛)

不过埃氏筛有很多是算重复了的,不行,必须把这个$\log \log n $给摘掉。

于是乎在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,就可以达到不重复的目的。

int p[N], v[N];
void Prime(int n) {
    int i, j;
    for (i = 2; i <= n; i++) {
        if (!v[i]) p[++p[0]] = i;
        for (j = 1; j <= p[0]; j++) {
            if (i * p[j] > n) break;
            v[i * p[j]] = 1;
            if (i % p[j] == 0) break;
        }
    }
}

$O(n)$使我疯狂!!!

GCD 和 LCM

约数与倍数

如果整数$a$能被整数$b$整除,$a$就叫做$b$的倍数,$b$就叫$a$的约数。

公约数与公倍数

几个整数中公有的约数,叫做这几个整数的公约数。

几个整数中公有的倍数,叫做这几个整数的公倍数。

最大公约数与最小公倍数

几个整数的公约数中,最大的叫做这几个数的最大公约数。

几个整数的公倍数中,最小的叫做这几个数的最小公倍数。

辗转相除法求GCD

int gcd(int a,int b)
{    
    if(a%b==0) 
    return b;        
    else return (gcd(b,a%b));
}

拓展欧几里得:

解$ax+by=\gcd(a,b)$这个方程。

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

LCM

$LCM(a,b)=(a/\gcd(a,b))\times b$

欧拉函数

欧拉函数表示的是小于等于$n$和$n$互质的数的个数。

显然,当$n$为素数,$\varphi(n)=n-1$

互质:多个数最大公因数只有1。

欧拉函数求法:

$\varphi(n)=n \times \frac{p_1-1}{p_1} \times \frac{p_2-1}{p_2}\times ...... \times \frac{p_r-1}{p_r}$

各个数值同整数唯一分解定理

欧拉函数模板

int euler(int n) {
    int ans = n;
    for (int i = 2; i * i <= n; i++)
        if (n % i == 0) {
            ans = ans / i * (i - 1);
            while (n % i == 0) n /= i;
        }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}
void phi(int n, int phi) {
    for (int i = 2; i <= n; i++) phi[i] = 0;
    phi[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!phi[i]) {
            for (int j = i; j <= n; j += i) {
                if (!phi[j]) phi[j] = j;
                phi[j] = phi[j] / i * (i - 1);
            }
        }
    }
}

欧拉定理和业余费马小定理

欧拉定理

与欧拉函数密切相关。

若$\gcd (a,m)=1$,则$a^{\varphi(m)}\equiv 1(\mod m)$

欧拉的计算

int euler(int x) {
    int i,ans=x,a=x;
    for(i=2; i*i<=a; i++) {
        if(a%i==0) {
            ans=ans-ans/i;
            while(a%i==0) {
                a=a/i;
            }
        }
    }
    if(a>1) ans=ans-ans/a;
    return ans;
}

筛法

void Selcet_Euler(int n) {
    int i,j;
    for(i=1; i<=n; i++) phi[i]=i;
    for(i=2; i<=nli++) {
        if(phi[i]==i) {
            for(j=i; j<=n; j+=i) {
                phi[j]=phi[j]/i*(i-1);
            }
        }
    }
}

利用欧拉函数的性质($p$为素数):

  1. $phi(p)=p-1$

2.如果 $i \mod p = 0$,那么$phi (i \times p)=p \times phi(i)$

3.若$i \mod p \not = 0$,那么$phi(i\times p)=phi(i)\times (p-1)$

由此,可以提出欧拉函数的线性筛法:

void Phi() { 
    int i,j,tot=0;
    for(i=2; i<=N; i++) {
        if(Mark[i]==false) {
            Prime[++tot]=i;   
            phi[i]=i-1;
        }
        for( j=1; j<=tot && i*Prime[ j]<=N; j++) {
            Mark[i*Prime[ j]]=true;
            if(i%Prime[ j]==0) {
                phi[i*prime[ j]]=phi[i]*Prime[ j];
                break;
            }
            else phi[i*Prime[ j]]=phi[i]*(Prime[ j]-1);
        }
    }
}

费马小定理

这个定理不费马,但费人

费马定理:设$p$是素数,$a$是整数,且$(a,p)=1$,则$a^{p-1} \equiv 1(\mod p)$

证明:考虑$1,2,3······(p-1)$这$(p-1)$个数字,同时乘上$a$,得到了$a,2a,3a······(p-1)a$。

$\because a \not = b(\mod p),(c,p)=1$

$\therefore ac \not = bc(\mod p)$

$\therefore 1 \times 2 \times 3......(p-1) \equiv a\times 2a\times 3a......(p-1)a(\mod p)$

$\therefore \gcd (1 \times 2 \times 3\times ...... \times (p-1),p)=1$

$\therefore a^{p-1} \equiv 1(\mod p)$

Miller-Rabin

前置:

1.费马小定理

2.二次探测定理

二次探测定理:如果$p$是一个素数,且$0 < x < p$,则方程$x^2 \equiv 1(mod p)$的解为$x=1,p-1$。

证明显然$x^2-1 \equiv 0(\mod p)$

$\therefore (x+1)(x-1) \equiv 0(\mod p)$

$\because p$为素数

$\therefore x=1$或者$x=p-1$

模板

bool MR(__int128 n) {
    __int128 a,x,y,d,r=0;
    if(n==2) return 1;
    if(n<3 || n%2==0) return 0;
    d=n-1;
    while(d%2==0) d/=2,r++;
    for(__int128 i=1;i<=30;i++) {
        a=rand()%(n-2)+2,x=qmi(a,d,n);
        for(__int128 i=1;i<=r;i++) {
            y=x*x%n;
            if(y==1 && x!=1 && x!=n-1) return 0;
            x=y;
        }
        if(x!=1) return false;
    }
    return 1;
}

乘法逆元

逆元

给定正整数$a,p$,如果有$ax \equiv 1(\mod p)$,且$a$与$p$互质,则称$x$的最小正整数解为$a \mod p$的逆元。

递推求逆元:

inv[1] = 1;
for (int i = 2; i <= n; i++) inv[i] = (mod - mod / i) * inv[mod % i] % mod;

拓展欧几里得:

辗转相除法的基础上求得的用于计算满足$\gcd(a,b)=ax+by$的整系数x和y。

使用ex-欧几里得来求逆元:

void exgcd(int a,int b,int &x,int &y) {
    if(b == 0) {
        x = 1; y = 0;
        return ;
    }
    exgcd(b,a%b,x,y);
    int t = x;  
    x = y;
    y = t - a / b * y;
}
posted @   changwenxuan  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示