前两天做了一道题是关于模运算的。模就是我们常说的取余。例如4 % 6 = 4,6 % 4 = 2。模运算的运算规则和四则运算类似。但是除法除外,有关这一点我们在后面会详细讲。
首先我们先介绍一下模运算的运算规则:
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p) % p
(a * b) % p = (a % p * b % p) % p
(a ^ b) % p = ((a % p) ^ b ) % p
模运算的结合律:
((a + b) % p + c) % p= (a + (b + c) % p) % p
((a * b) % p * c) % p = (a * (b * c) % p ) % p
交换律:
(a + b) % p = (b+a) % p
(a * b) % p = (b * a) % p
分配率:
((a +b) % p * c) % p = ((a * c) % p + (b * c) % p) % p
上文我们可以看出,除了除法之外模运算的运算规则和四则运算类似。关于模运算的除法运算我们需要了解一个概念叫逆元。
逆元是指指数学领域群G中任意一个元a,都在G中有唯一的逆元a‘,具有性质a×a'=a'×a=e,其中e为该群的单位元。在模运算中,单位元便是1。举个例子,求4关于7的乘法逆元,就是求一个数x,使4 * x % 7 = 1。下面我们来介绍求取逆元的算法:
第一种方法是循环求解法:给定模m和数x,在1 ~ m – 1中检查是否有x * i mod m = 1。
第二种方法是扩展欧几里得算法。欧几里得算法的依据是最大公约数定理:对任意的非负整数a和任意正整数b,gcd(a,b) = gcd(b,a mod b).
扩展欧几里得算法为:
Extend-Ecuclid(a,b):
If b == 0:
Then return(a,1,0)
(d1,x1,y1) = Extend-Ecuclid(b,a mod b)
(d,x,y) = (d,y1,x1-[a / b] * y1)
Return (d,x,y)
这里x是a的系数,y是b的系数。
在求a * x mod m = 1时,就是求a * x + m * y = 1的过程。那么我们需要的就是a的系数x。因此可以用欧几里得算法求解。欧几里得算法的C++过程为:
void ext_gcd(int a,int b,int &d,int &x,int &y){
if (b==0){
d=a;x=1;y=0;
return;
}
ext_gcd(b,a%b,d,y,x);
y-=a/b*x;
}
int main(){
scanf("%d%d",&m,&n);
ext_gcd(m,n,d,x,y);
printf("%d
",(x+n)%n);
return 0;
}