读书人

线性同缺和扩展欧几里得的运用小结

发布时间: 2013-09-06 10:17:17 作者: rapoo

线性同余和扩展欧几里得的运用小结

内容回顾:

在数论中,线性同余方程是最基本的同余方程,“线性”表示方程的未知数次数是一次,即形如:
ax≡b (mod n)的方程。此方程有解当且仅当 b 能够被 a 与 n 的最大公约数整除(记作 gcd(a,n) | b)。这时,如果 x0 是方程的一个解,那么所有的解可以表示为:
{x0+kn/d|(k∈z)}
其中 d 是a 与 n 的最大公约数。在模 n 的完全剩余系 {0,1,…,n-1} 中,恰有 d 个解。

扩展欧几里德算法是用来在已知a, b求解一组x,y使得ax+by = Gcd(a, b) =d(解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。

在我具体的做题过程中遇到了一些中国剩余定理的题目,基本上也都是可以用扩展欧几里德算法解决的,而在求解线性同余方程组时,一般用扩展欧几里德解决,而且我习惯只写一个扩展欧几里德调用函数,因为它也可以求得gcd,根本就不需要再用一个欧几里德算法求最大公约数。

中国剩余定理也有一些整理:传送阵


例题:

POJ1061 青蛙的约会

这是一道最简单的线性同余题目,题意中文(目测也没什么外国人看我blog)就不多说了,,,一个扩展欧几里德搞定。。。不过,青蛙的约会确实戳中泪点了,码农的爱情~

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<cmath>#include<set>#include<vector>#include<stack>#define mem(a,b) memset(a,b,sizeof(a))#define FOR(a,b,i) for(i=a;i<=b;++i)#define For(a,b,i) for(i=a;i<b;++i)#define N 1000000007using namespace std;inline void RD(int &ret){    char c;    do    {        c=getchar();    }    while(c<'0'||c>'9');    ret=c-'0';    while((c=getchar())>='0'&&c<='9')    {        ret=ret*10+(c-'0');    }}inline void OT(int a){    if(a>=10)    {        OT(a/10);    }    putchar(a%10+'0');}__int64 exdgcd(__int64 a,__int64 b,__int64 &x,__int64 &y){    __int64 l,r;    if(b==0)    {        x=1;        y=0;        return a;    }    r=exdgcd(b,a%b,x,y);    l=x;    x=y;    y=l-a/b*y;    return r;}int main(){    __int64 a,b,c,x1,x2,y1,y2,p,sum,x,y,x0,y0,lx,ly,rx,ry,l,r;    scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&x1,&x2,&y1,&y2);    if(a==0&&b==0)    {        if(c==0)        {            sum=(x2-x1+1)*(y2-y1+1);        }        else        {            sum=0;        }    }    else if(a==0)    {        if((-c)%b==0)        {            y0=(-c)/b;            if(y0>=y1&&y0<=y2)            {                sum=(x2-x1+1);            }            else            {                sum=0;            }        }        else        {            sum=0;        }    }    else if(b==0)    {        if((-c)%a==0)        {            x0=(-c)/a;            if(x0>=x1&&x0<=x2)            {                sum=(y2-y1+1);            }            else            {                sum=0;            }        }        else        {            sum=0;        }    }    else    {        p=exdgcd(a,b,x,y);        if((-c)%p!=0)        {            sum=0;        }        else        {            x=(x*(-c))/p;            y=(y*(-c))/p;            lx=(x1<=x||(x1-x)*p%b==0)?((x1-x)*p/b):((x1-x)*p/b+1);            rx=(x2>=x||(x2-x)*p%b==0)?((x2-x)*p/b):((x2-x)*p/b-1);            ly=(y1<=y||(y-y1)*p%a==0)?((y-y1)*p/a):((y-y1)*p/a-1);            ry=(y2>=y||(y-y2)*p%a==0)?((y-y2)*p/a):((y-y2)*p/a+1);            if(lx>rx)            {                swap(lx,rx);            }            if(ly>ry)            {                swap(ly,ry);            }            if(ry>=lx&&rx>=ly)            {                l=max(lx,ly);                r=min(rx,ry);                sum=r-l+1;            }            else            {                sum=0;            }        }    }    printf("%I64d\n",sum);    return 0;}

最后附上Matrix67神的线性同余和扩展欧几里德解析,很有意思:mod&&exdgcd

读书人网 >编程

热点推荐