一、欧几里德算法又称辗转相除法,用于计算两个正整数a,b的最大公约数。
定理:gcd(a,b) = gcd(b,a%b)
{
if(!b)
return a;
return gcd(b,a%b);
//return b?gcd(b,a%b):a;
}
二、扩展欧几里德: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
{
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;
}
三、同余定理:
给定正整数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 solve()
{
int n,flag=1;
ll a1,r1,a2,r2,x0,y0;
scanf("%d",&n);
scanf("%lld%lld",&a1,&r1);
for(int i=1;i<n;i++){
scanf("%lld%lld",&a2,&r2);
ll a=a1,b=a2,c=r2-r1;
ll d=exgcd(a,b,x0,y0);//d=gcd(a1,a2)
if(c%d)
flag=0;
int t=b/d;
x0=(x0*(c/d)%t+t)%t;//求x0的最小正整数解
r1=a1*x0+r1;
a1=a1*a2/d;
}
if(!flag)
return -1;
return r1;
}
七、中国剩余定理
当线性同余方程组中的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;
}