扩展欧几里得&&中国剩余定理(学习笔记)

匆匆过客 提交于 2020-05-01 04:20:26

原本是想把CRT、扩展CRT、欧几里得、扩展欧几里得都写在这,但由于博主太菜,刚刚才会EXCRT qwq

在退组边缘徘徊的我果然还是菜了一点啊!!!

布吉岛为什么但就是想奶一口gql省队稳了2333

不闲扯了,进入正题!


欧几里得(gcd)&&扩展欧几里得(exgcd):

先来一个众人皆知的欧几里得算法:$gcd\ (\ a,b\ )=gcd\ (\ b,a\ mod\ b\ )$

证明过程自己完成,这里不多加叙述

再来普及一个简单的裴蜀定理:若a,b是整数,且 $gcd(a,b)=d$,那么一定存在整数 $x,y$,使得$ax+by=d$ 成立。

裴蜀定理证明请看这里(主要是因为我之前打了一段后发现没证完然后就懒得打了qwq)

那么 $\bf\Huge\text{扩展欧几里得}​$ 来了!!!

扩展欧几里得算法:可以用来求解 $ax+by=gcd(a,b)$ ,也就是求同余方程 $ax\equiv gcd(a,b)(mod\ b)$ 的解

算法过程及解如下:

我们要求解 $ax+by=gcd(a,b)$ 其实主要是想算出 $x$ 的值,$y$ 是一个辅助解

然后我们构造这么一个式子:$bx_1+(a\ mod\ b)y_1=gcd(b,(a\ mod\ b))$ ,根据欧几里得算法,我们可得出 $bx_1+(a\ mod\ b)y_1=ax+by$ ,不妨把 $a\ mod\ b$ 变成 $a-b*(a/b)$ ,然后带入原式:


$bx_1+(a-b*(a/b))y_1=ax+by$

$bx_1+ay_1-b*(a/b)y_1=ax+by$

$ay_1+b(x_1-(a/b)y1)=ax+by$


那么我们求出了一组解:$x=y_1,y=x_1-(a/b)y_2$

然后将我们求解的两个式子对比一下:


$ax+by=gcd(a,b)$

$bx_1+(a\ mod\ b)y_1=gcd(b,(a\ mod\ b))$


是不是发现了什么?是不是有点像欧几里得算法?

然后我们按这种方式递推下去,直到 $b=0$ ,那么:


$ax+by=gcd(a,b)$

$ax=gcd(a,0)$


显然 $gcd(a,0)=a,x=1$ ,此时已经和 $y$ 的值没有关系了,即此时 $y$ 的值是任意数,但是这里建议把 $y$ 赋成 $0$ ,可以避免在返回中爆 $long\ long$ 。

之后我们已经求出来了关于同余方程的一个解 $x$ ,虽然 $x$ 不一定是最小的,但显然 $x$ 加上或减去 $b$ 是没有任何影响的,所以用一个 $x = (x % b + b) % b$ 就可以了求出满足同余方程的最小正整数解了

上代码:

void exgcd(int a,int b,int &x,int &y)
{//x,y都是要返回的值
    if(b==0)
    {
        x=1,y=0;
        return;
    }
    exgcd(b,(a%b),x,y);//递归
    int xx=y;//记录一下解
    y=x-(a/b)*xx,x=xx;
    return;
}

至此,扩展欧几里得讲解完毕qwq


中国剩余定理(CRT):

中国剩余定理其实真的不难qwq

一般情况下我们是要求解如下式子:

$\begin{cases} x\equiv a_1(\mod b_1)\quad \ x\equiv a_2(\mod b_2)\quad \ ...\quad \ x\equiv a_n(\mod b_n)\quad \ \end{cases}$

其中所有的 $b_1,b_2...b_n​$ 都互质,这里的 $a_i​$ 都小于 $b_i​$ 。

首先我们构造一个数 $B=b_1b_2...*b_n​$ ,那么显然当我们求出 $x​$ 之后加上或减去 $B​$ 都是成立的。

接下来考虑对于每一个同余方程的处理:

对于同余式 $x\equiv a_k(\mod b_k)$ ,我们可以构造一个 $B_k=B/b_k$ ,显然 $gcd(B_k,b_k)=1$ ,根据裴蜀定理可得:存在整数 $i,j$ 使得 $iB_k+jb_k=1$ ,即 $iB_k\equiv 1(\mod b_k)$ 。因为 $iB_k\ mod\ b_k=1$ ,那么有 $a_iiB_k\ mod\ b_k=a_i$ ,$i$ 可以通过扩展欧几里得求得,所以该同余方程的一个解是 $x=a_ii*B_k$ 。

再回到整个方程组,我们继续构造一个数 $x=a_1i_1B_1+a_2i_2B_2+...+a_ni_nB_n$ ,那么这个数就是同余方程组的一个解。因为对于第 $k$ 个同余方程,$B_{1...n}$ 中除 $B_k$ 之外所有数都是 $b_k$ 的倍数,所以同余方程是成立的。

放一下CRT的代码:

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 xx=y;
    y=x-(a/b)*xx,x=xx;
    return;
}//扩展欧几里得求解同余方程

lt china()
{
    for(int i=1;i<=n;i++) N*=B[i];
    for(int i=1;i<=n;i++)
    {
        int a=N/B[i],b=B[i],x=0,y=0;
        exgcd(a,b,x,y);//此处的x还要变成最小正整数解
        ans+=a*((x%b+b)%b)*A[i];
    }
    return (ans%N+N)%N;
}

扩展中国剩余定理(EXCRT)

好了,同样是形如下面的式子:

$\begin{cases} x\equiv a_1(\mod b_1)\quad \ x\equiv a_2(\mod b_2)\quad \ ...\quad \ x\equiv a_n(\mod b_n)\quad \ \end{cases}​$

只不过这次不保证所有的 $b_1,b_2,...,b_n$ 互质

因为不互质,所以我们无法像CRT一样使用扩欧。

考虑你已经求出来了前 $k-1​$ 个同余方程的解,得到的解为 $ans​$ ,设 $lcm​$ 为前 $k-1​$ 个方程中所有的 $b_i​$ 的最小公倍数,则前 $k-1​$ 个方程的解为 $x=ans+ilcm​$ ,而我们只需要确定一个 $i​$ 使得 $ans+ilcm\equiv a_k(\mod b_k)​$ ,然后更新一下 $lcm​$ 就好了。

又是一波转化:


$ans+i*lcm\equiv a_k(\mod b_k)$

$i*lcm\equiv a_k-ans(\mod b_k)$


注意:此处的 $lcm$ 和 $b_k$ 不一定互质,需要稍加处理,设 $gcd=gcd(lcm,b_k),c=(a_k-ans)\ mod\ b_k$ ,由上式可得:

$ilcm+hb_k=c$


由裴蜀定理可得此方程有解的必要条件是 $gcd|c$ ,于是继续变形:


$i/gcdlcm+hb_k/gcd=c/gcd$

$i/gcd*lcm\equiv c/gcd(\mod b_k/gcd)$


此时 $gcd(lcm,b_k/gcd)=1$ ,对于上面这个方程,我们依然可以先求出一个 $j$ 满足 $j*lcm\equiv 1(\mod b_k/gcd)$ ,然后再乘以 $c/gcd$ 倍就好了。

具体代码中有解释:

int exgcd(int a,int b,int &x,int &y)
{//扩展欧几里得,一并求出gcd
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    int res=exgcd(b,(a%b),x,y);
    int xx=x;
    x=y,y=xx-(a/b)*y;
    return res;
}

int mul(int s,int p,int mod)
{//这是一个快速乘,防止s*p爆long long
    int res=0;
    while(p)
    {
        if(p%2) res=(res+s)%mod;
        s=(s+s)%mod;
        p/=2;
    }
    return res%mod;
}

int EXCRT()
{
    m=b[1],ans=a[1];//第一个方程要特殊处理,直接赋值就好了
    for(int i=2;i<=n;i++)
    {
        int x,y,c=(a[i]-ans%b[i]+b[i])%b[i];
        //c就是前面的ak-ans
        int gcd=exgcd(m,b[i],x,y);
        x=mul(x,c/gcd,b[i]/gcd);
        //这一段我也弄了好久,最后终于搞懂了
        //大致把x为什么要乘c/gcd,和%(b/gcd)的原因写在上面了
        //不懂欢迎提问
        ans+=x*m;//更新ans
        m*=(b[i]/gcd);//更新lcm
        ans=(ans%m+m)%m;
    }
    return (ans%m+m)%m);
}

终于更完了qwq心累

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!