一点初等数论(扩展欧几里得,求逆元的三种方法)

以前遇到数论题直接懵逼,今天开始好好搞搞基础的数论知识。
一下内容证明我可能会省略,毕竟我太弱了….
.
.
.
.
.

1.模运算

几个常用的定律:

( a + b ) mod p = ( a mod p + b mod p ) mod p

( a * b ) mod p = ( (a mod p) * (b mod p) ) mod p

c * ( a mod p ) = ( c *a ) mod ( c *b ) ————————条件:(c*y!=0)

.
.
.
.

2.欧几里得算法

其实就是求最大公约数的辗转相除法
以下是抄来的证明,毕竟我太菜………..

.
.
.
.

首先考虑一下:

对于任意两个正整数 a,b ,都有:

a=kb+r  (k,r∈N)

所以有:

r=a%b  (在这里,%指的是取余运算)

然后我们假设 c 是 a 和 b 的最大公约数,即

c=gcd(a,b)

然后,我们就能得到:

 c|a    c|b  (x|y 表示 x 能够整除 y , y能被x整除 , 也就是y/x是整数)

然后又因为上面那个式子,有:

r=a−kb

所以有:

c|r

那么我们就可以知道,既然a和b的因数也是b和(a%b)的因数,那么它们的最大公因数肯定也是相同的。

整合一下上面的式子,我们可以得到:

c=gcd(b,r)

gcd(a,b)=gcd(b,a%b)     ----------gcd(a,b)表示a和b的最大公约数

而且

gcd(a,0) =  a

.
.
.
.
辗转相除法函数代码:

int gcd(int a,int b)//就是欧几里得算法函数,即辗转相除法,求gcd(a,b)
{
    int c;
    while(b!=0)
    {
        c=a;
        a=b;
        b=c%b; 
    }
    int ans=a;
    return ans;
}

这里还有一个点:lim ( a , b ) * gcd ( a , b ) =a * b ————————-这里lim( a, b )表示a和b的最小公倍数

.
.
.
.

3.扩展欧几里得算法

由于我实在是菜鸡,只能把别人的证明截屏下来

dalao的博客传送门:https://blog.sengxian.com/algorithms/gcd-extgcd

一点初等数论(扩展欧几里得,求逆元的三种方法)_第1张图片

一点初等数论(扩展欧几里得,求逆元的三种方法)_第2张图片
一点初等数论(扩展欧几里得,求逆元的三种方法)_第3张图片

.
.
.
.
这里有一道例题:https://www.luogu.org/problemnew/show/P1082

题目就是求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数

可能乍一看,ax ≡ 1 (mod b)跟上面的ax+by=gcd(a,b)这一个方程不太一样啊,没事,让我们来推导一下。
.
.

首先,题目保证了b是素数,即gcd(a,b)一定是1

我们设r=a*x%b, 有a*x=b*k+r
然后ax ≡ 1 (mod b)就转换为了a*x-b*k=1

然后我们再设 y=-k,方程就转换成了 a*x+b*y=1

a*x + b*y = gcd(a,b) = 1

就是妥妥的扩展欧几里得算法嘛!!! 递归求x的值就好啦!!!!

这里我还要提一下:我们递归求出来的x可能并不是最小正整数,还看是负数,我们这时候就需要处理一下。需要将x mod p,然后加上p(为了搞定负数),再mod p,代码就是:x = (x%p+p) % p;

#include
#include
#include
using namespace std;
long long x,y,n;//最好定全局变量
void exgcd(long long a,long long b)
{
    if(b==0) //当b=0时就是遇到了特解,可以递归回去算答案了
    {
        x=1,y=0;
        return ;
    }
    exgcd(b,a%b);
    long long k;
    k=x;
    x=y;
    y=k-(a/b)*y;
}
int main()
{
    long long a,p;
    scanf("%d%lld",&a,&p);
    exgcd(a,p);
    cout<<(x%p+p)%p;
    return 0;
}

4.乘法逆元

以下内容有些摘抄自dalao博客,传送门:https://www.luogu.org/blog/zjp-shadow/cheng-fa-ni-yuan

一点初等数论(扩展欧几里得,求逆元的三种方法)_第4张图片

算逆元的三个方法:

第一个方法:
一点初等数论(扩展欧几里得,求逆元的三种方法)_第5张图片

inline void exgcd(LL a,LL b)//扩展欧几里得算法求乘法逆元
{
    if(b==0)
    {
        x=1,y=0;
        return ;
    }
    exgcd(b,a%b);
    LL k;
    k=x;
    x=y;
    y=k-(a/b)*y;
}

.
.
.
.

第二个方法:
一点初等数论(扩展欧几里得,求逆元的三种方法)_第6张图片

int quick(int x,int p)//快速幂求乘法逆元,谨记,p是一个素数
{
    int ans=1;
    int d=p-2;
    while(d)
    {
        if(d%2==1)
        {
            ans*=x;
            ans%=p;
        }
        x*=x;
        x%=p;
        d/=2;
    }
    return ans;
}

.
.
.
.
第三个方法:
一点初等数论(扩展欧几里得,求逆元的三种方法)_第7张图片

这里有一个模板题目,就是洛谷的 P3811 【模板】乘法逆元
题目传送门:https://www.luogu.org/problemnew/show/P3811

#include
#include
#include
using namespace std;
long long x,y,n,f[3000010];
void work(long long n,long long p)//线性求逆元,时间复杂度O(n) 
{
    f[1]=1;
    for(long long i=2;i<=n;i++)
    {
        f[i]=-(p/i)*f[p%i];
        f[i]=(f[i]%p+p)%p;
    }
}
int main()
{
    long long a,p,b,n,i;
    cin>>n>>p;
    work(n,p); 
    for(long long i=1;i<=n;i++)
    {
        printf("%lld\n",f[i]);//处理出   最小正整数!!
    }

    return 0;
}

你可能感兴趣的:(蒟蒻的模板)