简单数论杂烩

前言:这是笔者根据 oiwiki,一些大佬的博客和自己的理解写出来的(主要是给自己看的)博客。\(\LaTeX\) 与代码部分均为笔者手打。如有抄袭请联系笔者。

前置算法:欧几里得法求最大公约数,快速幂,欧拉筛(线性筛)。

1. 定理

1.1 费马小定理

结论:设 \(p\) 为质数,则 \(a^{-1} \equiv 1 \pmod p\)\(a\) 不为 \(p\) 的倍数)。

证明:

显然对于两数 \(a,b\),若 \(\gcd(a,b)=1\)\(ab \equiv 0 \pmod p\),则有 \(a \equiv 0 \pmod p\)\(b \equiv 0 \pmod p\)

引理:设 \(\gcd(a,p)=1\),对于 \(1\)\(p-1\),每个数乘 \(a\) 在模 \(p\) 的意义下是互不相同的,且对应 \(1\)\(p-1\) 每个数。

为什么?反证法,若存在两个数 \(n,m\) 满足 \(1 \le n,m \le p-1\)\(n \neq m\),使得 \(na \equiv ma \pmod p\),则有 \((n-m)a \equiv 0 \pmod p\),所以需要满足 \(n-m \equiv 0 \pmod p\) 或者 \(a \equiv 0 \pmod p\)

\(a\)\(p\) 互质,所以 \(n-m \equiv 0 \pmod p\)。那么 \(|n-m| \ge p-1\) 也就不满足条件。

我们将 \(1\)\(p-1\) 的每个数相乘,将 \(a\)\(2a\),……,\((p-1)a\) 相乘,那么它们在模 \(p\) 意义下相等,即 \(\displaystyle \prod_{i=1}^{p-1} i \equiv a^{p-1} \prod_{i=1}^{p-1} i \pmod p\)

所以 \(\displaystyle (a^{p-1}-1) \prod_{i=1}^{p-1} i \equiv 0 \pmod p\)

因为 \(\displaystyle \prod_{i=1}^{p-1} i \ge 0\),所以 \(a^{p-1}-1 \equiv 0 \pmod p\),即 \(a^{p-1} \equiv 1 \pmod p\)


1.2 裴蜀定理

结论:对于不定方程 \(ax+by=c\),当 \(\gcd(a,b) \mid c\) 时方程有整数解。

证明:

\(d=\gcd(a,b)\),当 \(d>1\) 时,若 \(d \nmid c\) 则方程无整数解,否则两边同时除以 \(d\),转化为 \(d=1\) 的情况。

\(d=1\) 时,考虑 \(ax \bmod b\) 是否可以凑出 \(0\)\(b-1\) 的任意整数。根据 1.1 中给出的引理,只需要 \(x\)\(0\) 取到 \(b-1\) 即可。

\(ax+by=by'+r(0 \le r \le b-1)\),取 \(\displaystyle y'= \lfloor \frac{c}{b} \rfloor,r=c \bmod b\),可得 \(ax+by=c\)


2. 一些东西

2.1 扩展欧几里得算法

用途:扩展欧几里得算法可以在 \(O(\log_2 \max(a,b))\) 的时间复杂度内求出二元一次不定方程 \(ax+by=\gcd(a,b)\) 的一组可行整数解。

流程:

根据欧几里得算法有 \(\gcd(a,b)=\gcd(b,a \bmod b)\)

所以方程 \(bx+(a \bmod b)y=\gcd(b,a \bmod b)=\gcd(a,b)\) 有整数解。解这个不定方程得到一组整数解 \((x',y')\)

于是

\[\displaystyle \begin{aligned} ax+by &= bx'+(a \bmod b)y' \\ &= bx'+(a - \lfloor \frac{a}{b} \rfloor \times b)y' \\ &= ay'+bx'-b \times \lfloor \frac{a}{b} \rfloor \times y' \\ &= ay'+b(x'-\lfloor \frac{a}{b} \rfloor \times y') \end{aligned} \]

\(\biggl\{^{\displaystyle x=y'}_{\displaystyle y=x'-\lfloor \frac{a}{b} \rfloor \times y'}\),不断递归缩小问题规模,我们就可以在使用欧几里得算法求解 \(\gcd(a,b)\) 的同时求解 \(ax+by=\gcd(a,b)\) 的一组整数解。边界情况,\(b=0\) 时,有\(\gcd(a,b)x=\gcd(a,b)\),则 \(\biggl\{^{\displaystyle x=1}_{\displaystyle y=0}\) 为一组可行解。

int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        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;
}

2.2 逆元

定义:若 \(ax \equiv 1 \pmod m\),则称 \(x\)\(a\)\(\text{mod} \ m\) 意义下的乘法逆元。也可写作 \((a^{-1})_{m}\)

显然只有 \(\gcd(a,m)=1\)\((a^{-1})_{m}\) 存在。

求法:

费马小定理法:

要求 \(m\) 为质数。

根据费马小定理有 \(a^{p-1} \equiv a^{p-2} \times a \equiv -1 \pmod m\)

所以 \(a^{p-2} \equiv a^{-1} \pmod m\)。快速幂解决即可。


扩展欧几里得法:

无其他要求。

注意到 \(ax \equiv 1 \pmod m\) 可以转化成一个二元一次不定方程 \(ax-my=1\),而 \(\gcd(a,m)=1\),扩展欧几里得算法解出 \(x\) 即可。


离线 \(O(n)\) 求多个数逆元:

令这些数分别为 \(a_1,a_2,...,a_n\)。算出它们的前缀积 \(\displaystyle b_k=\prod_{i=1}^k a_i\)。令 \(b_0=1\)

求出 \((b_n^{-1})_m\),则 \(b_k^{-1} \equiv b_{k+1}^{-1} \times a_{k+1} \pmod m\)\(a_k^{-1} \equiv b_k^{-1} \times b_{k-1} \pmod m\)。总时间复杂度 \(O(n+\log_2 n)=O(n)\)

int m;
int a[N],b[N],inv_a[N],inv_b;
//...
inv_b=qpow(a,m-2,m);//int tmp;exgcd(b[n],m,inv_b,tmp);
inv_a[n]=inv_b*b[n-1];
for(int i=n-1;i>=1;i--){
    inv_b=1ll*inv_b*a[i+1]%m;
    inv_a[i]=1ll*inv_b*b[i-1]%m;
}

2.3 中国剩余定理(参考 oiwiki)

用途:中国剩余定理(Chinese Remainder Theorem,简称 CRT)可以用于求解同余方程组

\[\left\{ \begin{aligned} x \equiv a_1 & \pmod{m_1} \\ x \equiv a_2 & \pmod{m_2} \\ & \ \ \vdots \\ x \equiv a_n & \pmod{m_n} \\ \end{aligned} \right. \]

的解。其中 \(\forall i,j,1 \le i,j \le n,i \neq j\),有 \(\gcd(m_i,m_j)=1\)。(即模数两两互质)

流程:

  1. \(\displaystyle M=\prod_{i=1}^{n} m_i\)
  2. 对于每个方程,计算 \(\displaystyle \frac{M}{m_i}\)\(m_i\) 下的逆元 \(\displaystyle (\frac{M}{m_i})^{-1}\)
  3. 方程在模 \(M\) 意义下的唯一解为 \(\displaystyle x=\sum_{i-1}^{n} a_i \frac{M}{m_i} (\frac{M}{m_i})^{-1}\)

证明:

显然,当 \(i \neq j\) 时,有 \(\displaystyle \frac{M}{m_i} \equiv 0 \pmod {m_j}\),那么 \(\displaystyle \frac{M}{m_i} (\frac{M}{m_i})^{-1} \equiv \frac{M}{m_i} \equiv 0 \pmod {m_j}\)

根据逆元定义,\(\displaystyle \frac{M}{m_i} (\frac{M}{m_i})^{-1} \equiv 1 \pmod {m_i}\)

则对于第 \(i\) 个方程组,有:

\[\begin{aligned} \displaystyle x & \equiv \sum_{j=1}^{n} a_j \frac{M}{m_j} (\frac{M}{m_j})^{-1} & \pmod{m_i} \\ & \equiv a_i \frac{M}{m_i} (\frac{M}{m_i})^{-1} & \pmod{m_i} \\ & \equiv a_i & \pmod{m_i} \end{aligned} \]

这样就证明了 CRT 的正确性。

for(int i=1;i<=n;i++)
    M*=m[i];
for(int i=1;i<=n;i++){
    exgcd(M/m[i]%m[i],m[i],x,y);
    (ans+=(a[i]*M/m[i]*((x%m[i]+m[i])%m[i]))%M)%=M;
}

扩展

用于解决模数不互质的情况。

\(x \equiv a_1 \pmod{m_1}\)\(x \equiv a_2 \pmod{m_2}\)

将其转为不定方程,则有 \(x=m_1 x_1+a_1=m_2 x_2+a_2\)

那么 \(m_1 x_1-m_2 x_2=a_2-a_1\)

由裴蜀定理,当 \(\gcd(m_1,m_2) \nmid a_2-a_1\) 时,方程无解。

否则,通过扩欧得到一组可行解。

那么可将两个同余方程合并为一个方程 \(x \equiv m_1 x_1+a_1 \pmod{\text{lcm}(m_1,m_2)}\)

重复合成 \(n-1\) 次即可将 \(n\) 个同余方程合并成一个同余方程。

#define i128 __int128
for(int i=1;i<=n;i++){
    read(m);read(a);
    if(i==1){
        M=m;
        x=a;
        continue;
    }
    i128 inv,tmp;
    i128 d=exgcd(M,m,inv,tmp);//m1x1-m2x2=a2-a1
    if((a-x)%d!=0){
        cout<<-1;
        return 0;
    }
    i128 mod=M*m/d;
    x=(inv*(a-x)/d%mod*M%mod+x)%mod;
    M=mod;
    x=(x%M+M)%M;
}

2.4 欧拉函数(参考 oiwiki)

定义:

欧拉函数 \(\varphi(n)\),表示 \(1\)\(n\) 中与 \(n\) 互质的数的个数。如 \(\varphi(8)=4\),因为在 \(1\)\(8\) 中有 \(1、3、5、7\)\(4\) 个数与 \(8\) 互质。

性质:

  1. \(p\) 为任意质数,则 \(\varphi(p)=p-1\)

  2. 欧拉函数是积性函数,即当 \(\gcd(a,b)=1\),有 \(\varphi(ab)=\varphi(a) \varphi(b)\)

  3. 对于任意正整数 \(n\)\(\displaystyle n=\sum_{d \mid n} \varphi(d)\)

  4. \(\displaystyle n=\prod_{i=1}^{x} p_i^{k_i}\)(其中 \(p_i\) 为质数),有 \(\displaystyle \varphi(n)=n \times \prod_{i=1}^{x} \frac{p_i-1}{p_i}\)

欧拉定理等学了之后再写。

求法:

质因数分解:

根据性质:\(\displaystyle \varphi(n)=n \times \prod_{i=1}^{x} \frac{p_i-1}{p_i}\),对 \(n\) 作质因数分解的同时计算 \(\varphi(n)\) 即可。

int phi(int x){
    int res=x;
    for(int i=2;i*i<=x;i++){
        if(x%i)continue;
        res=res/i*(i-1);
        while(n%i==0)x/=i;
    }
    if(n>1)res=res/x*(x-1);
    return res;
}

线性筛(也叫欧拉筛):

(名字里居然都有欧拉。欧拉好闪,拜谢欧拉。/bx)

以下是一个线性筛模板:

vector<int> pri;
bool flag[N];
void init(int n){
    for(int i=2;i<=n;i++){
        if(!flag[i])
            pri.push_back(i);
        for(int p:pri){
            if(i*p>n)break;
            flag[i*p]=flag;
            if(i%p==0)break;
        }
    }
}

注意到:对于一个合数 \(n\),由于线性筛确保每个合数只会被筛一次,所以 \(n\) 会被它的最小质因子筛掉。

设这个最小质因子为 \(p\),令 \(\displaystyle n'=\frac np\),我们分两种情况进行讨论:

  1. \(p \mid n'\),则 \(n'\) 包含 \(n\) 的所有质因子,则:

\[\begin{aligned} \displaystyle \varphi(n) &= n \times \prod_{i=1}^{x} \frac{p_i-1}{p_i} \\ &= p \times n' \times \prod_{i=1}^{x} \frac{p_i-1}{p_i} \\ &= p \times \varphi(n') \end{aligned} \]

  1. \(p \nmid n'\),则根据欧拉函数的积性,有

\[\begin{aligned} \displaystyle \varphi(n) &= \varphi(p) \times \varphi(n') \\ &= (p-1) \times \varphi(n') \end{aligned} \]

分情况计算即可。

vector<int> pri;
int phi[N];
bool flag[N];
void init(int n){
    phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!flag[i]){
            pri.push_back(i);
            phi[i]=i-1;
        }
        for(int p:pri){
            if(i*p>n)break;
            flag[i*p]=flag;
            if(i%p==0){
                phi[i*p]=p*phi[i];
                break;
            }
            phi[i*p]=(p-1)*phi[i];
        }
    }
}

2.5 数论分块

用于在 \(O(\sqrt{n})\) 复杂度内求出 \(\displaystyle \sum_{i=1}^{n} f(i) \lfloor \frac{n}{i} \rfloor\)

结论:

使得 \(\displaystyle \lfloor \frac{n}{i} \rfloor = \lfloor \frac{n}{j} \rfloor\) 成立且 \(i \le j \le n\) 的最大的 \(j=\displaystyle \lfloor \frac{n}{\lfloor \frac{n}{i} \rfloor} \rfloor\)

计算过程:


持续更新中。。。

posted @ 2025-04-21 22:29  z_Sqr  阅读(23)  评论(0)    收藏  举报