一、歐幾里德算法又稱輾轉相除法,用於計算兩個正整 a,b的最大公約數。
定理:gcd(a,b) = gcd(b,a%b) 。代碼實現如下:
#include<stdio.h>
#define ll long long
ll gcd(ll m,ll n)
{
if(n==0)
return m;
return gcd(n,m%n);
}
int main()
{
ll m,n;
ll x;
while(scanf("%lld %lld",&m,&n)!=EOF)
{
x=gcd(m,n);
printf("%lld\n",x);
}
return 0;
}
二、擴展歐幾里德:ax+by=c
x=x0+b/gcd(a,b)*t;
y=y0+a/gcd(a,b)*t;
由ax+by=gcd(a,b) gcd(a,b)=gcd(b,a%b)
- ax+by=gcd(b,a%b)=bx0+(a%b)y0 a%b=a-a/b*b
- ax+by=ay0+b*(x0-a/b*y0)
- 所以可得出:x=y0 y=x0-a/b*y0
- 擴展歐幾里得最大的用法就是求x,y的最小正整數解。爲了求x,y的最小正整數解首先求得是 ax+by=gcd(a,b)的解。求出的x,y乘以c/gcd(a,b)。這就是ax+by=c的解而要想求最小正整數解就要看此通解公式x=x0+b/gcd(a,b)*t.其中x0=x*c/gcd;要想求最小正整數解那麼就是 x=x0+b/gcd(a,b)*t兩邊同時對b/gcd(a,b)取餘此時在加工一下就是x=(x%(b/gcd)+(b/gcd))%(b/gcd)。
代碼如下:
#include<stdio.h>
#define ll long long
ll gcd(ll m,ll n)
{
if(n==0)
return m;
return gcd(n,m%n);
}
ll exgcd(ll a,ll b,ll &x,ll &y){//求擴展歐幾里得中ax+by=gcd(a,b)的解
if(!b){
x=1;
y=0;
return a;
}
ll ans=exgcd(b,a%b,x,y);
ll temp=x;
x=y;
y=temp-a/b*y;
return ans;
}
ll cal(ll a,ll b,ll c)//求擴展歐幾里德最小正整數解
{
ll x,y;
ll gcd=exgcd(a,b,x,y);
if(c%gcd!=0)
return -1;
x*=c/gcd;
b/=gcd;
return (x%b+b)%b;
}
int main()
{
ll a,b;
ll c;
ll x,y;
ll x0,y0;
while(scanf("%lld %lld %lld",&a,&b,&c)!=EOF)
{
gcd1=exgcd(a,b,x,y);//此時求出來的解是ax+by=gcd(a,b)的解
x=cal(a,b,c);
y=(c-b*y)/a;
printf("%lld %lld\n",x,y);
}
return 0;
}
三.1、同餘定理:
給定正整數m,a/m與b/m所得餘數相同,稱a、b同餘。
a≡b(mod m),存在整數k,使a=b+km;
a+-*c≡b+-*c(mod m)可以轉化爲擴展歐幾里德
代碼如下:
四、逆元
對於正整數a和m,如果有ax≡1(mod m),那麼把這個同餘方程中x的最小正整數解叫做a模m的逆元。
1、擴展歐幾里德求逆元:由同餘定理 ax≡1(mod m)可化爲
ax=1+km ax-km=1
可直接用擴展歐幾里德求出a的逆元x
2、費馬小定理求逆元(當m爲素數時):ax≡1(mod m) --> x=
推導過程:
五、一元線性同餘方程
定義:形如ax≡b(mod m), 且x是未知整數的同餘式稱爲一元線性同餘方程。
定理:a,b,m是整數且m>0,gcd(a,m)=d,如果d|b(‘|’的意思爲整除即b%d==0),則方程恰有d個模m不同餘的解否則方程無解。
可以直接用擴展歐幾里德求
ll f()
{
//ax≡b(mod m)
ll a,b,m;
scanf("%lld%lld%lld",&a,&b,&m);
ll x,y;
ll d=exgcd(a,m,x,y);
if(b%d)
return -1;
x=x*(b/d)%m;
for(int i=0;i<d;i++)
printf("%lld ",(x+i*m/d)%m);
}
六、線性同餘方程組
X≡r1(mod a1)
X≡r2 (mod a2)
X≡r3 (mod a3)
………………
X≡rn (mod an)
X=r1+a1*x
X=r2+a2*y
a1*x-a*2y=r2-r1
由擴展歐幾里得通解x=x0+a2/gcd*t
帶回原式 X=r1+a1*x0+a1*a2/gcd*t
由同餘定理可知X≡r1+a1*x0 (mod a1*a2/gcd)
然後再令r1=r1+a1*x0
a1=a1*a2/gcd
可將X化爲X≡r1 (mod a1)
然後再與後幾項依次合併就可得出X。
ll f(){
//ax≡b(mod m)
ll a,b,m;
scanf("%lld%lld%lld",&a,&b,&m);
ll x,y;
ll d=exgcd(a,m,x,y);
if(b%d)
return -1;
x=x*(b/d)%m;
for(int i=0;i<d;i++)
printf("%lld ",(x+i*m/d)%m);
}
七、中國剩餘定理
當線性同餘方程組中的m1、m2、m3..mn兩兩互素時,則線性同餘方程組
X≡a1(mod m1)
X≡a2 (mod m2)
X≡a3 (mod m3)
………………
X≡an (mod mn)
有模M=m1*m2*m3..*mn的唯一解。
Mi=M/mi
a1*M1*p1+a2*M2*p2+a3*M3*p3+..+an*Mn*pn就是同餘方程組的解
ll China()
{
int n;
ll M=1,a[1005],m[1005];
ll Mi,x0,y0,ans=0,d;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld%lld",&m[i],&a[i]);
for(int i=0;i<n;i++)
M*=m[i];
for(int i=0;i<n;i++)
{
Mi=M/m[i];
d=exgcd(Mi,m[i],x0,y0);
ans=(ans+Mi*x0*a[i])%M;
}
return (ans+M)%M;
}