数论入门2——gcd,lcm,exGCD,欧拉定理,乘法逆元,(ex)CRT,(ex)BSGS,(ex)Lucas,原根,Miller-Rabin,Pollard-Rho

数论入门2

另一种类型的数论...

GCD,LCM

定义\(gcd(a,b)\)为a和b的最大公约数,\(lcm(a,b)\)为a和b的最小公倍数,则有:

将a和b分解质因数为\(a=p1^{a1}p2^{a2}p3^{a3}...pn^{an},b=p1^{b1}p2^{b2}p3^{b3}...pn^{bn}\),那么\(gcd(a,b)=\prod_{i=1}^{n}pi^{min(ai,bi)},lcm(a,b)=\prod_{i=1}^{n}pi^{max(ai,bi)}\)(0和任何数的最大公约数是这个数,最小公倍数是0)

显然成立的吧。

所以我们有\(gcd(a,b)*lcm(a,b)=ab\)。

求\(gcd(a,b)\)的方法:

首先我们有:\(gcd(a,b)=gcd(b,a-b)(a>=b)\)

显然的啊,两个数相减怎么可能影响他们的最大公约数,毕竟是“公”约数,相减肯定还存在这个因子啊。

所以拓展一下我们就有:\(gcd(a,b)=gcd(b,a \% b)(a>=b)\)

取模就是不断相减,所以也是成立的呀。

所以我们可以写出简洁的代码:

int gcd(int a,int b){return !b?a:gcd(b,a%b);}

很显然这个复杂度是log的,每次至少减少一半。

lcm的话,\(a/gcd(a,b)*b\)即可。

然后呢,gcd和lcm具有交换律和结合律:

\(gcd(a,b,c)=gcd(gcd(a,b),c)=gcd(c,b,a)\)

所以求多个数的gcd或lcm的时候就可以递推求啦。

还有一个东西就是\(gcd(ka,kb)=k*gcd(a,b)\),也是显然的。

exGCD

对于方程\(ax+by=c\),显然若\(gcd(a,b)|c\)的时候才有解。

因为不整除的话\(ax+by\)肯定有\(c\)不包含的因子,那样的话怎么可能有解呢?

然后呢,我们可以通过这样的方式快速借助求gcd的过程求出\(ax+by=gcd(a,b)\)的一组解。

当\(a=gcd(a,b),b=0\)时,显然\(x=1,y=0\)。

令\(a = b, b = a \% b\),则有方程\(b *x1 +(a \% b) * y1 = gcd(b, a \% b)\)

又因为\(gcd(a, b) = gcd(b, a \% b)\),且\(a \% b = a - b * ?a / b?\)

则\(b * x1 + (a - b * ?a / b?) * y1 =gcd(a, b)\)

整理得:\(a * y1 +b * (x1 - ?a / b? *y1) = gcd(a, b)\)

所以原方程中:\(x = y1, y = x1 - ?a / b? *y1\)。于是我们只要递归求出\(x1, y1\)就能求出\(x, y\)。

我们现在已经求得了\(ax +by = gcd(a, b)\)的解,那么对于方程\(ax + by = c (gcd(a, b) | c)\)呢?

因为已经知道\(a *x1 +b * y1 = gcd(a, b)\)的解\(x1, y1\),左右两边同乘以\(c / gcd(a, b)\) 得:

\(a * x1 * c / gcd(a, b) +b * y1 * c / gcd(a, b) = c\)

则原方程的一组解\(,x2 = x1 * c / gcd(a, b), y2 = y1 * c / gcd(a, b)\)

由此得出解集\(,{(x, y) | x = x2 + k * b / gcd(a, b), y = y2 - k * a / gcd(a, b), k ∈ Z}\)

对于线性同余方程\(ax\equiv c\quad(mod\quad b)\),我们怎么做呢?

显然可以转化成\(ax+by=c\)的形式,然后直接用扩欧解决啦。

贴个代码:

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

欧拉定理

费马小定理:

若p是质数,且\(gcd(a,p)=1\),则\(a^{p-1}\equiv1(mod\quad p)\)。

欧拉定理:

若\(gcd(a,p)=1\),则\(a^{\varphi(p)}\equiv1(nod \quad p)\)。

扩展欧拉定理:

\(a^b\equiv \begin{cases} a^{b\%\varphi(p)}~~~~~~~~~~~gcd(a,p)=1\\ a^b~~~~~~~~~~~~~~~~~~gcd(a,p)\neq1,b<\varphi(p)\\ a^{b\%\varphi(p)+\varphi(p)}~~~~gcd(a,p)\neq1,b\geq\varphi(p) \end{cases}~~~~~~~(mod~p)\)

\(\varphi\)为欧拉函数。

证明:欧拉定理和扩展欧拉定理的证明

有个作用就是在算\(a^b\)的时候对b进行取模,使运算更高效,具体见luogu欧拉定理模板题

乘法逆元

若\(gcd(a,b)=1,\)\(ax\equiv 1(mod~p)\),则称x为a在模p意义下的乘法逆元。

那么求法就很显然了。

欧拉定理:a在模p意义下的逆元为\(a^{\varphi(p)-1}\)。

exGCD:当做一个同余方程求,但是要通过+kp的方式变为一个正数。

此外还有一个线性求逆元的算法。

首先,1在任何模数下的逆元都是1。

然后设\(p=i*k+r,r<i,1<i<p\)。

那么我们有\(i*k+r\equiv 0(mod~p)\)

两边同时乘上\(i^{-1}*r^{-1}\)得:

\(k*r^{-1}+i^{-1}\equiv 0(mod~p)\)

\(i^{-1}\equiv -k* r^{-1}(mod~p)\)

因为\(k=\lfloor p/i\rfloor,r=p\%i\),所以我们得到了逆元的递推式:

a[i]=-(p/i)*a[p%i]%p;

以及提一句,逆元是完全积性函数,从定义式里面就能看出来。

对于一个前缀积的序列的话,我们可以求出最后一项的逆元,然后\(O(n)\)递推回去,实际上逆元可以理解为模意义下的\(\frac{1}{x}\),怎么递推的话也很显然了,以阶乘为例:

fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
ifa[n]=ksm(fac[n],P-2);
for(int i=n-1;~i;i--) ifa[i]=ifa[i+1]*(i+1)%P;

还有就是:

\((a/b)\%p=(a\%(bp))/ p\)

证明:

\((a/b)\%p=a/b-?(a/b)/p?*p\)

\(=a/b-?a/(b*p)?*p\)

\(=a/b-?a/(bp)?*b*p/b\)

\(=(a\%(bp) )/p\)

CRT

已知系数全部为1的线性同余方程组:

\(x \equiv a_i(mod ~p_i)\),其中\(p_i\)两两互质,求x的最小非负整数解。

那么我们考虑这样一个思路:

从1到n考虑每个同余方程组,我们设\(M=\prod_{i=1}^{n}p_i\),那么当我们考虑到第i个方程的时候,我们设\(T=\frac{M}{p_i}\),那么我们发现把第i个方程的解\(x\)加上\(kT\)的话,\(x+kT\)带到别的同余方程组的余数不会改变。

假设我们已经求出了前\(i-1\)个方程的通解\(x\),求出了第\(i\)个方程的一个解\(x_i\),那么显然,\(Tx_i+x\)是前\(i\)个方程的解。

我们用exGCD求出第i个线性同余方程组\(Tx_i\equiv a_i(mod~p_i)\)的解,一步步合并即可,因为\(p_i\)显然和\(T\)互质,所以实际上是求出逆元之后乘上\(a_i\)。

exCRT

已知系数全部为1的线性同余方程组:

\(x \equiv a_i(mod ~p_i)\),其中\(p_i\)都是正整数,求x的最小非负整数解。

上面的算法失效了。为什么?都不一定互质了怎么可能还去求逆元?

所以我们要考虑一个新的思路:

假设我们已经求出了前\(i-1\)个方程的通解\(x\),设\(M\)为前i-1个数的lcm,那么我们发现\(x+kM\)如果能够满足第\(i\)个方程,那么前i个方程就都解出来啦。

我们写个式子:\(x+kM \equiv a_i(mod~p_i)\),移项得\(kM \equiv a_i-x(mod ~p_i)\)。

那么我们解出来k之后,前i个方程的通解就出来啦,一步步做下去即可。

贴个代码:

ll mul(ll x,ll y,ll p){ll g=0;for(;y;y>>=1,x=(x+x)%p) if(y&1) g=(g+x)%p;return g;}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b){x=1;y=0;return a;}
    ll g=exgcd(b,a%b,y,x);y-=a/b*x;
    return g;
}
for(int i=1;i<=n;i++) scanf("%lld%lld",&b[i],&a[i]);
ans=a[1];M=b[1];
for(int i=2;i<=n;i++)
{
    ll A=M,B=b[i],c=(a[i]%B-ans%B+B)%B,x,y;
    ll gcd=exgcd(A,B,x,y),d=B/gcd;
    if(c%gcd) return 0;x=mul(x,c/gcd,d);
    ans+=x*M;M*=d;ans=(ans%M+M)%M;
}

注意一下,因为是求lcm,所以那个B要除以gcd。

BSGS

exBSGS

原根

Lucas

exLucas

Miller-Rabin

Pollard-Rho

原文地址:https://www.cnblogs.com/CK6100LGEV2/p/10352130.html

时间: 2024-09-29 20:31:04

数论入门2——gcd,lcm,exGCD,欧拉定理,乘法逆元,(ex)CRT,(ex)BSGS,(ex)Lucas,原根,Miller-Rabin,Pollard-Rho的相关文章

gcd &amp; lcm &amp;exgcd

int lcm(int a, int b) { return a / gcd(a, b) * b; } int gcd(int a,int b) { return b ? gcd(b,a%b):a; } int exgcd(int a,int b,int &x,int &y) { if(!b) { x=1; y=0; return a; } int r=exgcd(b,a%b,x,y); int t=y; y=x-(a/b)*y; x=t; return r; //gcd } 原文地址:h

扩展欧几里得算法、裴蜀定理与乘法逆元

扩展欧几里得算法 扩展欧几里得算法(扩O)能在求gcd(a,b)的同时求出丢番图方程ax+by=gcd(a, b)的解. 然而怎么求呢?我们观察gcd(a, b)=gcd(b, a%b),所以设如下两个方程: ax+by = gcd(a,b) = d: bx'+(a%b)y' = gcd(b,a%b): 明显gcd(a,b) = gcd(b,a%b),也就是ax+by = bx'+(a%b)y'. 为了求得x与y,我们需要保证a,b不变,所以:ax+by = bx'+(a%b)y' = bx'+

T106021 【模板】乘法逆元(快速幂)

题目地址 注意点: 使用exgcd求乘法逆元需额外进行(相对)较多操作,建议使用快速幂求乘法逆元. #include<cstdio> #include<iostream> #define ll long long using namespace std; int n,p; int poww(int a,int b){ ll ans=1,tmp=a; while(b){ if(b&1){ ans*=tmp; ans%=p; } tmp=tmp*tmp; tmp%=p; b&g

Uva 11388 GCD LCM ( 数论 )

Uva  11388 GCD LCM( 数论 ) 题意: 求是否存在a,b 使得lcm(a,b) = L, gcd(a,b) = G,不存在输出-1,存在输出a,b,且a尽可能小 分析: 强行暴力是不可能的数据很大,要用llu,这里有两种思路 思路一: 由题意可知 a*b = G*L 保证a = G的倍数的情况下,枚举a再判断G*L能否整除a,最后判断b是否为a的倍数.a从G开始扫到sqrt(G*L) //输入两个整数G,L //找出a,b 使得 gcd(a,b) = G lcm(a,b) =

gcd以及exgcd入门讲解

gcd就是最大公约数,gcd(x, y)一般用(x, y)表示.与此相对的是lcm,最小公倍数,lcm(x, y)一般用[x, y]表示. 人人都知道:lcm(x, y) = x * y / gcd(x, y) 证明起来也不是很难: (这真的是我自己写的,因为博客园不支持这格式--) 至于gcd的求法,想必各位在高中都学过辗转相除法和更相减损之术,这里只讲辗转相除法(更相减损之术略慢) 首先不妨设 x ≤ y,则gcd(x, y)  =gcd(x, x +y) = gcd(x, y - x).所

数论——gcd&amp;&amp;lcm

gcd(a, b),就是求a和b的最大公约数 lcm(a, b),就是求a和b的最小公倍数 然后有个公式 a*b = gcd * lcm     ( gcd就是gcd(a, b), ( ????? ) 简写你懂吗) 解释(不想看就跳过){ 首先,求一个gcd,然后... a / gcd 和 b / gcd 这两个数互质了,也就是 gcd(   a / gcd ,b / gcd  )  =  1,然后... lcm = gcd *  (a / gcd) * (b / gcd) lcm = (a *

浅谈欧拉定理及乘法逆元

浅谈欧拉定理及乘法逆元 本篇随笔简单讲解一下信息学奥林匹克竞赛数论部分欧拉定理及乘法逆元这一知识点.介绍的内容大致分为这么几个部分:"同余的基本概念.费马小定理.欧拉定理及其推论.乘法逆元". 同余的基本概念 同余的概念啊非常简单啦:如果两个整数\(a,b\)除以一个数\(m\)的余数相等的话,那么就叫做\(a,b\)在模\(m\)的意义上同余. 记作: \[ a\equiv b\,\,\,(mod\,\,m) \] 那么根据同余的这个定义,我们很容易能推导出一个性质:如果两个数\(a

uva 10006 数论入门题

这是一个入门的数论题目 , 只需要简单的找素数和快速幂取模 题意:输入一个数 n , 如果这个数是非素数 , 问是不是 这个2~n-1区间的所有数都满足 ? 解法:由于数据量不大 , 可以直接暴力求解 解法1: 暴力求解 #include <iostream> #include <string.h> #include <stdio.h> using namespace std; long long prime[65010]; long long n; void init

扩展GCD 中国剩余定理(CRT) 乘法逆元模版

extend_gcd: 已知 a,b (a>=0,b>=0) 求一组解 (x,y) 使得 (x,y)满足 gcd(a,b) = ax+by 以下代码中d = gcd(a,b).顺便求出gcd 能够扩展成求等式 ax+by = c,但c必须是d的倍数才有解,即 (c%gcd(a,b))==0 注意求出的 x,y 可能为0或负数 =================================== 乘法逆元: a*b %n == 1 已知 a, n, 求b 就是乘法逆元 ============