基础数论学习笔记

目录

  • 整除
  • 质数
  • 积性函数
  • 模算术

整除

一般情况下暂不讨论负数
任何正整数都整除于0
g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,则称 a a a b b b互质

g c d gcd gcd l c m lcm lcm的关系:

l c m ( a , b ) = a b g c d ( a , b ) lcm(a,b)=\frac{ab}{gcd(a,b)} lcm(a,b)=gcd(a,b)ab

g c d gcd gcd的性质
  1. g c d ( a , b ) = g c d ( b , a − b ) gcd(a,b)=gcd(b,a-b) gcd(a,b)=gcd(b,ab)
  2. g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)
g c d gcd gcd的代码
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}

复杂度为 O ( log ⁡ max ⁡ ( a , b ) ) O(\log \max(a,b)) O(logmax(a,b))

质数

质数个数

公式:
定义 π ( n ) \pi(n) π(n)为不大于 n n n的质数的个数,则:
π ( n ) = O ( n log ⁡ n ) \pi(n)=O(\frac{n}{\log n}) π(n)=O(lognn)
n n n越大,答案越精准

唯一分解定理

对于任意一个 n ≥ 2 n \geq 2 n2,都有这样的唯一的分解式:
n = ∏ i = 1 m p i k i n=\prod_{i=1}^{m}{p_{i}^{k_i}} n=i=1mpiki
其中, p i p_{i} pi为不大于 n n n的质数, k i k_{i} ki为正整数
可以证明, m = O ( log ⁡ log ⁡ n ) m=O(\log\log n) m=O(loglogn)

质因数分解代码
//法一
for(int i=2;i<=n;++i)
{
    while(n%i==0)
    {
        num[++cnt]=i;
        n/=i;
    }
}
//法二
for(int i=2;i*i<=n;++i)
{
    while(n%i==0)
    {
        num[++cnt]=i;
        n/=i;
    }
}
if(n>1)num[++cnt]=n;
//法三
vector<int>p;//存储所有的质数
for(int i=1;i<p.size();++i)
{
    if(p[i]*p[i]>n)break;
    while(n%p[i]==0)
    {
        num[++cnt]=p[i];
        n/=p[i];
    }
}
if(n>1)num[++cnt]=n;

法一的复杂度为 O ( n ) O(n) O(n)
法二的复杂度为 O ( n ) O(\sqrt n) O(n )
法三的复杂度为 O ( n log ⁡ n ) O(\frac{\sqrt n}{\log n}) O(lognn )

求所有不大于 n n n的质数

筛法:

  1. 朴素筛:复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
  2. 埃氏筛:复杂度为 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
  3. 欧拉筛:复杂度为 O ( n ) O(n) O(n)
欧拉筛代码:
bool vis[N];
int num[N]
vis[1]=1;
for(int i=1;i<=n;++i)
{
    if(!vis[i])num[++cnt]=i;
    for(int j=1;j<=cnt&&num[j]*i<=n;++j)
    {
        vis[i*num[j]]=1;
        if(i%num[j]==0)break;
    }
}

积性函数

定义

f ( n ) f(n) f(n)为定义在正整数上的函数(一般数论函数较多),如果 f ( 1 ) = 1 f(1)=1 f(1)=1,且对于任意的正整数 a , b a,b a,b,若 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,,就有:
f ( a ∗ b ) = f ( a ) ∗ f ( b ) f(a*b)=f(a)*f(b) f(ab)=f(a)f(b)
我们称 f ( n ) f(n) f(n)为积性函数
若不要求 a , b a,b ab互质,这样的 f ( n ) f(n) f(n)称为完全积性函数

计算方法

首先是得到 n n n的唯一分解式: n = ∏ i = 1 m p i k i n=\prod_{i=1}^{m}{p_{i}^{k_{i}}} n=i=1mpiki

根据积性函数的性质可以得到以下计算式:
f ( n ) = ∏ i = 1 m p i k i f(n)=\prod_{i=1}^{m}{p_{i}^{k_i}} f(n)=i=1mpiki
求解 f ( p i k i ) f(p_{i}^{k_{i}}) f(piki)的方法由积性函数的性质决定,无一般方法求解

线性筛的过程中求解积性函数
bool vis [ N+1]; 
vector p ; 
int c [ N+1], f [ N+1]; 
void sieve()
{ 
    for (int i = 2; i <= N; ++ i)
    { 
        if(!vis [ i])
        { 
            p .push_back ( i); 
            for (int j = i , k = 1;; ++ k)
            { 
                c [ j] = j ; 
                f [ j] = cal ( i , k); 
                if ( j > N / i ) break ; 
                j *= i ; 
            } 
        } 
        for (int j = 0; i * p [ j] <= N; ++ j)
        { 
            vis [ i * p [ j]] = 1; 
            if ( i % p [ j] == 0)
            { 
                c [ i * p [ j]] = c [ i]* p [ j]; 
                f [ i * p [ j]] = f [ i / c [ i]]* f [ c [ i]* p [ j]]; 
                break ; 
            }
            c [ i * p [ j]] = p [ j]; 
            f [ i * p [ j]] = f [ i]* f [ p [ j]]; 
        } 
    } 
} 
积性函数举例
约数函数

定义 σ x ( n ) \sigma _{x}(n) σx(n) n n n的所有约数的 x x x次方的和,即:
σ x ( n ) = ∑ d ∣ n d x \sigma _{x}(n)=\sum_{d\mid n}{d^{x}} σx(n)=dndx
特别的, σ 0 ( n ) \sigma _{0}(n) σ0(n)表示的是 n n n的约数的个数,常常记为 d ( n ) d(n) d(n) τ ( n ) \tau(n) τ(n) σ 1 ( n ) \sigma _{1}(n) σ1(n)表示的是约数和,简记为 σ ( n ) \sigma(n) σ(n)

具体来说,对于 n n n的每一个质因子,我们都可以得到这样的式子:
τ ( p k ) = l + 1 \tau(p^{k})=l+1 τ(pk)=l+1
(+1的原因是要考虑1)
然后,我们把 n n n的唯一分解式带入后,根据乘法原理就可以得到 τ ( n ) \tau(n) τ(n)的计算式:
τ ( n ) = ∏ i = 1 m k i + 1 \tau(n)=\prod_{i=1}^{m}{k_{i}+1} τ(n)=i=1mki+1
由此可以证明 σ 0 ( n ) \sigma _{0}(n) σ0(n)为积性函数

对于质数 p p p和正整数 k k k,有:
σ x ( p k ) = ∑ i = 0 k ( p i ) x = ∑ i = 0 k ( p x ) i \sigma_{x}(p^{k})=\sum_{i=0}^{k}(p^{i})^{x}=\sum_{i=0}^{k}(p^{x})^i σx(pk)=i=0k(pi)x=i=0k(px)i
因此,当 x ≠ 0 x\neq0 x=0时,有:
σ x ( p k ) = ( p x ) k + 1 − 1 p x − 1 \sigma_{x}(p^{k})=\frac{(p^{x})^{k+1}-1}{p^{x}-1} σx(pk)=px1(px)k+11

欧拉函数

定义 φ ( n ) \varphi (n) φ(n) 为不大于 n n n的数中与 n n n互质的数的个数,即:
φ ( n ) = ∑ i = 1 n [ g c d ( i , n ) = 1 ] \varphi (n)=\sum_{i=1}^{n}[gcd(i,n)=1] φ(n)=i=1n[gcd(i,n)=1]
[ x ] [x] [x] x x x为真时值为 1 1 1

对于质数 p p p和正整数 k k k,有:
φ ( p k ) = p k − p k − 1 = p k − 1 ∗ ( p − 1 ) \varphi (p^{k})=p^{k}-p^{k-1}=p^{k-1}*(p-1) φ(pk)=pkpk1=pk1(p1)
可以证明 φ ( n ) \varphi (n) φ(n)为积性函数

欧拉函数的计算公式:
φ ( n ) = n ∏ p ∣ n ( 1 − 1 p i ) \varphi(n)=n\prod_{p\mid n}(1-\frac{1}{p_{i}}) φ(n)=npn(1pi1)

欧拉函数的性质:

  1. ∑ d ∣ n φ ( d ) = n \sum_{d\mid n}\varphi(d)=n dnφ(d)=n
  2. n n n为质数, φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n1
  3. gcd ⁡ ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1,则 φ ( a b ) = φ ( a ) φ ( b ) \varphi(ab)=\varphi(a)\varphi(b) φ(ab)=φ(a)φ(b)

欧拉函数的求解:

求解单个欧拉函数的值:

int tmp=phi_m=m;
    for(int i=2;i<=m;++i)
    {
        if(i*i>m)break;
        if(tmp%i==0)
        {
            phi_m=phi_m-phi_m/i;
            while(tmp%i==0)tmp/=i;
        }
    }
    if(tmp>1)phi_m=phi_m-phi_m/tmp;

线性递推求解多个欧拉函数的值:

void phi_n()
{
    phi[1]=1;
    for(int i=2;i<=N-10;++i)
    {
        if(!vis[i])
        {
            phi[i]=i-1;
            p.push_back(i);
        }
        for(int j=0;j<p.size()&&p[j]*i<=N-10;++j)
        {
            vis[i*p[j]]=1; 
            if(i%p[j]==0)
            {
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
            else phi[i*p[j]]=phi[i]*phi[p[j]];
        }
    }
}

模算术

取模

注意取模的定义(特指负数形式下)
a    m o d    n = { a − ⌊ a n ⌋ a ≥ 0 − ( − a    m o d    n ) a < 0 a\,\,mod\,\,n=\begin{cases} a-\lfloor \frac {a}{n} \rfloor & a\geq 0\\\\ -(-a\,\,mod\,\,n) & a\lt 0 \end{cases} amodn= ana(amodn)a0a<0

同余

( a − b )    m o d    n = 0 (a - b)\,\,mod\,\,n=0 (ab)modn=0,则称 a a a b b b同余,记作:
a ≡ b    ( m o d    n ) a\equiv b\,\,(mod\,\,n) ab(modn)
a a a b b b均取正整数时,此式等价于 a    m o d    n = b    m o d    n a\,\,mod\,\,n=b\,\,mod\,\,n amodn=bmodn

根据模运算的性质可得到同余的等价形式:
a ≡ b (   m o d   n ) ⟺ n ∣ ( a − b ) a\equiv b(\bmod n) \Longleftrightarrow n \mid (a-b) ab(modn)n(ab)

根据模运算的定义可以得到几个几个同余的性质:

假设 a ≡ b ( m o d n ) a \equiv b(mod n) ab(modn) c ≡ d (   m o d   n ) c\equiv d(\bmod n) cd(modn),可以得知:

  1. a + c ≡ b + d (   m o d   n ) a+c \equiv b+d (\bmod n) a+cb+d(modn)
  2. a c ≡ b d (   m o d   n ) ac \equiv bd(\bmod n) acbd(modn)
  3. k a ≡ k b (   m o d   n ) ka\equiv kb(\bmod n) kakb(modn)
  4. a m ≡ b m    (   m o d   n ) a^{m}\equiv b^{m}\,\,(\bmod n) ambm(modn)
  5. a b ≡ a c (   m o d   n ) ab\equiv ac(\bmod n) abac(modn),且 gcd ⁡ ( a , n ) = 1 \gcd(a,n)=1 gcd(a,n)=1,则 b ≡ c (   m o d   n ) b\equiv c(\bmod n) bc(modn),满足消去律
剩余类

把所有模 n n n后与 a a a同余的整数构成的集合叫做一个剩余类,记作 [ a ] [a] [a]

根据同余的性质可以推得: a ≡ b (   m o d   n ) ⇔ [ a ] = [ b ] a\equiv b(\bmod n) \Leftrightarrow [a]=[b] ab(modn)[a]=[b]

剩余类的运算满足:交换律、结合律,分配律

即: [ a ] + [ b ] = [ a + b ] , [ a ] ∗ [ b ] = [ a ∗ b ] [a]+[b]=[a+b],[a]*[b]=[a*b] [a]+[b]=[a+b],[a][b]=[ab]

模算术的基本性质

a 0 = a    m o d    n a_{0}=a\,\,mod\,\,n a0=amodn b 0 = b    m o d    n b_{0}=b\,\,mod\,\,n b0=bmodn,有:
a + b ≡ a 0 + b 0    ( m o d    n ) a ∗ b ≡ a 0 ∗ b 0    ( m o d    n ) \begin{split} a+b\equiv a_{0}+b_{0}\,\,(mod\,\,n)\\ a*b\equiv a_{0}*b_{0}\,\,(mod\,\,n) \end{split} a+ba0+b0(modn)aba0b0(modn)
对于任意的正整数 k k k,有:
a    m o d    n = ( a    m o d    k n ) m o d    n a\,\,mod\,\,n=(a\,\,mod\,\,kn)mod\,\,n amodn=(amodkn)modn
若有 k ∣ n k\mid n kn,则:
a k    m o d    n = a    m o d    k n k \frac{a}{k}\,\,mod\,\,n=\frac{a\,\,mod\,\,kn}{k} kamodn=kamodkn
证明如下:

a = m k a=mk a=mk

a k    m o d    n = m    m o d    n = m − n a    m o d    k n k = a − k n k = k ( m − n ) k = m − n \begin{split} \frac{a}{k}\,\,mod \,\,n=m \,\,mod \,\,n\\=m-n \\ \frac{a\,\, mod \,\,kn}{k}=\frac{a-kn}{k}\\\\=\frac{k(m-n)}{k}\\\\=m-n \end{split} kamodn=mmodn=mnkamodkn=kakn=kk(mn)=mn

模算术的基本运算
取模优化
template <class>T
inline T mod(T a)
{
    return a<p?a:a-p;
}

这个函数的速度优于内置的取模运算符,但不可以代替取模(仅仅在 a < 2 p a\lt 2p a<2p时可以使用)

快速幂(平方求幂法)
int power(int a, int b,int mod)
{ 
    int bas=a,num=1; 
    while(b)
    { 
        if(b&1) num = (num*bas)%mod; 
        bas=(bas*bas)%mod; 
        b>>=1;
    } 
    return num; 
}
龟速(快速)乘(加倍求积法)
#define int long long
int mul(int a, int b,int mod)
{ 
    int  num = 0; 
    while(b)
    { 
        if(b&1) num =(num+a)%mod; 
        if(b>1) a =(a+a)%mod;
        b>>=1; 
    } 
    return num; 
}

龟速乘的主要用途是为了防止炸精度,从而以牺牲时间复杂度为代价进行加倍求积

模乘法的逆元

逆元存在的意义是分数无法直接取模

a a a为正整数,若存在整数 b b b满足:
a   ∗   b ≡ 1    (    m o d    n ) a\,*\,b\equiv1 \,\,(\,\,mod\,\,n) ab1(modn)
则称 b b b a a a n n n的逆元,记为 a − 1 a^{-1} a1 1 a \frac{1}{a} a1

  • 当且仅当 g c d ( a , n ) = 1 gcd(a,n)=1 gcd(a,n)=1时, a a a n n n的逆元存在

  • a a a n n n的逆元在模 n n n意义下具有唯一性

费马小定理

p p p为质数, a a a p p p互质,则有:
a p − 1 ≡ 1    (    m o d    p ) a^{p-1}\equiv 1\,\,(\,\,mod\,\,p) ap11(modp)

证明如下:

已知 g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1,我们取一个数列如下:

1 , 2 , … , p − 1 1,2,\dots , p-1 1,2,,p1集体乘 a a a再模 p p p可以得到:
a , 2 a , … , ( p − 1 ) a   m o d   p    → 1 , 2 , … , p − 1 a,2a,\dots,(p-1)a \bmod p\,\,\to 1,2,\dots,p-1 a,2a,,(p1)amodp1,2,,p1
因为 a , 2 a , … , ( p − 1 ) a a,2a,\dots,(p-1)a a,2a,,(p1)a p − 1 p-1 p1个互不相同的数,模 p p p后势必得到 p p p个不同的数,因此可以得到上式

由上式我们可以得到:
1 × 2 × ⋯ × ( p − 1 ) ≡ a × 2 a × ⋯ × ( p − 1 ) a    (   m o d   p ) 1\times2\times\dots\times(p-1)\equiv a\times2a\times\dots\times(p-1)a\,\,(\bmod p) 1×2××(p1)a×2a××(p1)a(modp)
即:
( p − 1 )   !    ≡ a p − 1 ( p − 1 )   !    (   m o d   p ) (p-1)\,!\,\,\equiv a^{p-1}(p-1)\,!\,\,(\bmod p) (p1)!ap1(p1)!(modp)

又因为 g c d ( p , p − 1 ) = 1 gcd(p,p-1)=1 gcd(p,p1)=1,原式推导可得:
1 ≡ a p − 1    (   m o d   p ) 1\equiv a^{p-1}\,\,(\bmod p) 1ap1(modp)
证毕

注意:同余式可以两端同时乘逆元

由费马小定理可以得知:
a ∗ a p − 2 ≡ 1 (   m o d   p ) a*a^{p-2}\equiv 1(\bmod p) aap21(modp)
根据乘法逆元的定义可以得知:
a − 1 ≡ a p − 2 (   m o d   p ) a^{-1}\equiv a^{p-2} (\bmod p) a1ap2(modp)

由此,我们可以根据费马小定理,利用快速幂求解逆元

预处理逆元

假设 p p p为质数, n n n为正整数,求 [ 1 , n ] [1,n] [1,n]每个数模 p p p意义下的逆元

对每个数分别求逆元,时间复杂度为 O ( n l o g p ) O(nlogp) O(nlogp)

我们可以发现,逆元满足积性函数,因此可以用线性筛去求解,时间复杂度为 O ( n log ⁡ p log ⁡ n ) O(\frac{n\log p}{\log n}) O(lognnlogp)

(关于逆元是积性函数的证明,显然有 ( a b ) − 1 = a − 1 b − 1 (ab)^{-1}=a^{-1}b^{-1} (ab)1=a1b1

但显然我们有更优的方法

我们设 i ∈ [ 1 , n ] i \in [1,n] i[1,n],根据模运算的性质我们可以得到:
p = ⌊ p i ⌋ i    +    ( p   m o d   i ) p=\lfloor \frac{p}{i} \rfloor i \,\,+\,\,(p\bmod i) p=ipi+(pmodi)

对该式移项化简可以得到:
i − 1 ≡ − ⌊ p i ⌋ p   m o d   i (   m o d   p ) {i}^{-1}\equiv -\frac{\lfloor \frac{p}{i}\rfloor }{p\bmod i} (\bmod p) i1pmodiip(modp)
因为 p   m o d   i < i p \bmod i \lt i pmodi<i,因此递推计算的时间复杂度为 O ( n ) O(n) O(n)

以上方法推导简单,但不是最优的方法

一个明显的等式 1 i ! = i + 1 ( i + 1 ) ! \frac{1}{i!}=\frac{i+1}{(i+1)!} i!1=(i+1)!i+1,因此实际上,我们可以用 O ( log ⁡ p ) O(\log p) O(logp)的复杂度求出 1 n ! \frac{1}{n!} n!1,接下来进行递推便可得到任意的 1 i ! \frac{1}{i!} i!1,由此可以得到 1 i \frac{1}{i} i1

欧拉定理

n ≥ 2 n\geq 2 n2为整数, g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,则有:
a φ ( n ) ≡ 1 ( m o d    n ) a^{\varphi(n)}\equiv1 (mod\,\,n) aφ(n)1(modn)

特别的,若 n n n为质数, φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n1,欧拉定理便转化为费马小定理

用类似的方法可以得到:
a − 1 ≡ a φ ( n ) − 1    (   m o d   n ) a^{-1}\equiv a^{\varphi(n)-1}\,\,(\bmod n) a1aφ(n)1(modn)

利用这个式子便可以求任意模数下的逆元,但计算 φ ( n ) \varphi(n) φ(n)的复杂度较高( O ( n log ⁡ n ) O(\sqrt n\log n) O(n logn)),该式不如费马小定理常用

扩展欧拉定理

对于欧拉定理,我们可以将 a a a的指数一般化,得到一下情况
a b ≡ { a b   m o d   φ ( m )   (   m o d   m )                             gcd ⁡ ( a , m ) = 1 a b   (   m o d   m )                                                   gcd ⁡ ( a , m ) ≠ 1 , b < φ ( m ) a ( b   m o d   φ ( m ) ) + φ ( m )   (   m o d   m )            gcd ⁡ ( a , m ) ≠ 1 , b ≥ φ ( m ) a^{b}\equiv \begin{cases} a^{b\bmod \varphi(m)}\,(\bmod m)\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\gcd(a,m)=1\\ \\ a^{b}\,(\bmod m)\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\gcd(a,m)\neq1,b\lt \varphi(m)\\ \\ a^{(b\bmod \varphi(m))+\varphi(m)}\,(\bmod m)\,\,\,\,\,\,\,\,\,\,\gcd(a,m)\neq1,b\geq\varphi(m) \end{cases} ab abmodφ(m)(modm)gcd(a,m)=1ab(modm)gcd(a,m)=1,b<φ(m)a(bmodφ(m))+φ(m)(modm)gcd(a,m)=1,bφ(m)

降幂公式

n , k n,k n,k为任意的正整数, a a a为任意整数,可以得到:
a k ≡ a min ⁡ ( k , k 0 )    (   m o d   n ) a^{k}\equiv a^{\min(k,k_{0})}\,\,(\bmod n) akamin(k,k0)(modn)
其中, k 0 = ( k   m o d   φ ( n ) ) +    φ ( n ) k_{0}=(k\bmod \varphi(n))+\,\,\varphi(n) k0=(kmodφ(n))+φ(n)

由此我们就可以实现降幂的操作,从而降低时间复杂度

欧拉降幂

根据扩展欧拉定理,我们可以对于降幂的操作分三类情况进行讨论,然后分别进行降幂操作

代码如下:

int read() 
{ 
    int b=0;
    bool flag=0;
    char c; 
    while (!isdigit(c = getchar())); 
    for (; isdigit(c); c = getchar()) //由于读入的系数会很大,因此要一边读入一边取模降幂
    { 
        b = b * 10 + c - '0'; 
        if (b >= phi) 
        { 
            flag = true; 
            b %= phi; 
        } 
    } 
    if (flag) 
    { 
        b += phi ;
    } 
    return b;
}
欧几里得算法与扩展欧几里得算法
欧几里得算法(辗转相除法)

a , b a,b a,b为任意正整数且 a > b a\gt b a>b,则存在正整数组 q , r q,r q,r满足:
a = q 0 b + r 0 b = q 1 r 0 + r 1 r 0 = q 1 r 1 + r 2 … … r n − 2 = q n r n − 1 + r n r n − 1 = q n + 1 r n \begin{split} a=q_{0}b+r_{0}\\ b=q_{1}r_{0}+r_{1}\\ r_{0}=q_{1}r_{1}+r_{2}\\ \dots \dots\\ r_{n-2}=q_{n}r_{n-1}+r_{n}\\ r_{n-1}=q_{n+1}r_{n} \end{split} a=q0b+r0b=q1r0+r1r0=q1r1+r2……rn2=qnrn1+rnrn1=qn+1rn
其中, b > r 0 > r 1 > ˙ r n b \gt r_{0}\gt r_{1}\dot \gt r_{n} b>r0>r1>˙rn

以上的一组式子实际上是 求解 gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b)的展开

扩展欧几里得算法

通过以上的式子我们可以总结得出,对于任意的正整数 k k k,都会满足:
r k = r k − 2 − q k r k − 1 r_{k}=r_{k-2}-q_{k}r_{k-1} rk=rk2qkrk1
因此,我们可以通过递归求解出整数(可以为负数) x , y x,y x,y,满足:
r n = a x + b y r_{n}=ax+by rn=ax+by

特别的,当 gcd ⁡ ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1时,原式可化简为 a x ≡ 1 (   m o d   b ) ax\equiv 1(\bmod b) ax1(modb),此时, x x x a a a在模 b b b意义下的逆元

扩欧代码

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

b = 0 b=0 b=0时,我们显然有一组解 x = 1 , y = 0 x=1,y=0 x=1,y=0

b > 0 b\gt 0 b>0时,由 gcd ⁡ ( a , b ) = g c d ( b , a   m o d   b ) \gcd(a,b)=gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)可知:假设存在 x , y x,y x,y满足 a x + gcd ⁡ ( b , a   m o d   b ) y = gcd ⁡ ( b , a   m o d   b ) ax+\gcd(b,a\bmod b)y=\gcd(b,a\bmod b) ax+gcd(b,amodb)y=gcd(b,amodb)

那么就有 a y + b ( x − ⌊ a b ⌋ ) = gcd ⁡ ( a , b ) ay+b(x-\lfloor\frac{a}{b}\rfloor)=\gcd(a,b) ay+b(xba⌋)=gcd(a,b)

裴蜀定理

对于任意的正整数 a , b a,b a,b,都存在 x , y x,y x,y满足 a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)

裴蜀定理也可以扩展到 n n n个正整数,即:

对于任意 n n n个正整数 a 1 , a 2 , … , a n a_{1},a_{2},\dots,a_{n} a1,a2,,an,都存在 n n n个整数 x 1 , x 2 , … , x n x_{1},x_{2},\dots,x_{n} x1,x2,,xn,满足:
a 1 x 1 + a 2 x 2 + ⋯ + a n x n = gcd ⁡ ( a 1 , a 2 , … , a n ) a_{1}x_{1}+a_{2}x_{2}+\dots+a_{n}x_{n}=\gcd(a_{1},a_{2},\dots,a_{n}) a1x1+a2x2++anxn=gcd(a1,a2,,an)
这个方程亦可用扩欧进行求解

扩欧最常用的一个方面是求解不定方程 a x + b y = c ax+by=c ax+by=c

根据裴蜀定理可以得到:

c ∣ gcd ⁡ ( a , b ) c\mid \gcd(a,b) cgcd(a,b),该方程肯定有整数解

我们可以求出 a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)的一组特解 ( x ′ , y ′ ) (x',y') (x,y),然后得到了 a x + b y = c ax+by=c ax+by=c的一组特解:
( c gcd ⁡ ( a , b ) x ′ , c gcd ⁡ ( a , b ) y ′ ) (\frac{c}{\gcd(a,b)}x',\frac{c}{\gcd(a,b)}y') (gcd(a,b)cx,gcd(a,b)cy)

最后可以得到该方程的通解:

( c gcd ⁡ ( a , b ) x ′ + k b gcd ⁡ ( a , b ) , c gcd ⁡ ( a , b ) y ′ − k a gcd ⁡ ( a , b ) ) (\frac{c}{\gcd(a,b)}x'+k \frac{b}{\gcd(a,b)} ,\frac{c}{\gcd(a,b)}y'-k\frac{a}{\gcd(a,b)}) (gcd(a,b)cx+kgcd(a,b)b,gcd(a,b)cykgcd(a,b)a)

中国剩余定理( C R T CRT CRT)

问题背景:

求解同余方程组:
{ x ≡ a 1 (   m o d   m 1 ) x ≡ a 2 (   m o d   m 2 ) … … x ≡ a n (   m o d   m n ) \begin{cases} x\equiv a_{1}(\bmod m_{1})\\ x\equiv a_{2}(\bmod m_{2})\\ \dots \dots\\ x\equiv a_{n}(\bmod m_{n}) \end{cases} xa1(modm1)xa2(modm2)……xan(modmn)

其中, m 1 , m 2 … , m n m_{1},m_{2}\dots,m_{n} m1,m2,mn两两互质

对此我们可以去构造一组解

M = ∏ i = 1 n m i M=\prod _{i=1}^{n}m_{i} M=i=1nmi,我们可以构造:
x = ∑ i = 1 n M i ( a i M i − 1   m o d   m i ) x=\sum_{i=1}^{n}M_{i}(a_{i}M_{i}^{-1}\bmod m_{i}) x=i=1nMi(aiMi1modmi)

其中, M i M_{i} Mi表示 M m i \frac{M}{m_{i}} miM,可以证明该解在模 M M M意义下唯一

代码实现:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,ans;
int a[100100],b[100100];
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;
    return d;
}//利用exgcd求逆元(费马小定理可能不适用)
signed main()
{
    scanf("%lld",&n);
    int M=1;
    for(int i=1;i<=n;++i)
    {
        scanf("%lld%lld",&b[i],&a[i]);
        M*=b[i];//构造M
    }
    for(int i=1;i<=n;++i)
    {
        int mod=b[i],mi=M/b[i];
        int x=0,y=0;
        exgcd(mi,mod,x,y);//x为Mi的逆元
        ans=(ans+a[i]*mi*(x<0?x+b[i]:x));
    }
    printf("%lld",ans%M);
    return 0;
}
扩展 C R T CRT CRT

问题背景:求解同余方程组
x = a i (   m o d   m i ) x=a_{i}(\bmod m_{i}) x=ai(modmi)
此时不要求 m i m_{i} mi两两互质

对于每一个 m i m_{i} mi,我们对其进行质因数分解,得到 m i = ∏ p i , j k i , j m_{i}=\prod p_{i,j}^{k_{i,j}} mi=pi,jki,j ,然后将原方程进行拆分。对于 p p p相同的方程进行合并,从而转化为模数两两互质的方程组。若合并时出现矛盾,则原方程组无解

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值