定义:a,b是整数,形如 ax≡b(mod m) ,且x是未知整数的同余式称为一元线性同余方程。
定理:a,b,m是整数且m>0, gcd(a,m)=d ,如果d|b,则方程恰好有d个模m不同余的解,否则方程无解。
由同余方程的定义式可得 ax+my=b ,这个方程称为二元一次不定方程。
解一元线性同余方程
设d=gcd(a,m),由定理可知若不满足d|b,那么方程无解;否则:
a=d∗a0
m=d∗m0
那么方程变为: a0x+m0y=b/d(二元一次不定方程两边同除以d)
由于此时 gcd(a0,m0)=1 ,因此可以运用扩展欧几里得算法得出方程 a0x+m0y=b/d 的解x (等价于a0x(b/d)+m0y(b/d)=1) ,
虽然x不唯一,但是属于一个模m剩余系,由定理可知,共有d个模m剩余类满足方程,其代表分别为:(由 a0x≡bd(mod m0)得到 )
x,x+m0,x+2m0...x+(d−1)m0
例题(POJ 1061青蛙的约会)
- 题目大意
在一个圆环上有两只青蛙A和B,从0点自东向西为正方向,两只青蛙的位置分别为x,y,A每次跳m,B每次跳n,环总长为L.两只青蛙同时出发,两只青蛙落在同一点视为相遇,问最少经过几次跳跃两只青蛙相遇。
- 分析
设k次相遇,则有 x+mk≡y+nk(mod L)
转化成 (m−n)k≡(y−x)(mod L) 就变成了一个裸的线性同余方程的问题了
- 代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
typedef long long int LL;
LL Gcd(LL a,LL b)
{
return b==0?a:Gcd(b,a%b);
}
LL Exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
else
{
LL ans=Exgcd(b,a%b,x,y);
LL temp=x;
x=y;
y=temp-(a/b)*y;
return ans;
}
}
//这种写法方便理解
LL f(LL a,LL b,LL m)//求解一元线性同余方程
{
LL x,y,d;
LL a0,m0;
d=Gcd(a,m);
if(b%d!=0)return -1;
a0=a/d;
m0=m/d;
Exgcd(a0,m0,x,y);
x=x*b/d;
x=(x%m0+m0)%m0;
return x;
}
//这种写法更简洁
LL f2(LL a,LL b,LL m)//求解一元线性同余方程
{
LL x,y,d;
d=Exgcd(a,m,x,y);
if(b%d!=0)return -1;
x=x*(b/d)%m;
x=(x%(m/d)+(m/d))%(m/d);
return x;
}
int main()
{
LL x,y,m,n,L;
LL A,B,C,xx,yy,d;
while(scanf("%I64d %I64d %I64d %I64d %I64d",&x,&y,&m,&n,&L)!=EOF)
{
LL ans=f2(n-m,x-y,L);
if(ans==-1)cout<<"Impossible"<<endl;
else cout<<ans<<endl;
}
return 0;
}