同余应该是数论中比较基础的一个东西了。感觉挺重要的。。。高中没学好到大学来补了。
涉及3个数,a,b,m。就是a % m == b % m.
可以写成:a b(mod m)。
一、同余及其一些性质
同余有一些显然性质,有的时候会有很大功效。(不列举了,一般书上都有的)。
这样的题根据数据类型有不同的解法:
这里m还在数据类型可表示的范围内,当m极大时,就要用到欧拉降幂这个东西。
这里说一下m还在数据类型可存储范围内的做法。
n^1 n (mod k)
n^2 (n mod 7) * (n mod 7) mod 7
n^4 (n^2 mod 7) * (n^2 mod 7) mod 7
......
将m进行二进制分解,然后递推得到结果,当然递归也是可以的。
二、同余方程
GCD:最大公约数 辗转相除法 一句话:
int GCD(int x, int y){
return y == 0 ? x : GCD(y, x % y);
}
LCM: 最小公倍数
int LCM(int x, int y){
return x * y / GCD(x, y);
}
扩展欧几里得算法:
这个算法是用来求已知a,b时,求一组p,q使得p*a+q*b=GCD(a,b)。由某些定理,解一定存在。
因为GCD(a,b) = GCD(b, a%b)。
p*a + q*b = GCD(a,b) = GCD(b, a % b)
即:p*a + q*b = p * b + q * (a % b) = p * b + q * (a - a / b * b) = q * a + (p - a/b * q) * b.
a,b都在不停的减小,最后b减小到0, 可以得出p=1,q=0。然后递归回去,得到最终的p,q。
同余方程:
int exgcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
int k = exgcd(b, a % b, x, y);
h = x;
x = y;
y = h - (a / b) * y;
return k;
}
同余方程:
定理一:该同余方程等价于a * x + b * y = c。有解的充分必要条件是c % GCD(a, b) = 0.我们可以先用扩展欧几里得算法得到
a * x + b * y = GCD(a, b)的一组解(x0,y0).然后两边同除GCD(a, b),同乘c,得到a * x0 * c / GCD(a, b) + b * y0 * c/GCD(a, b) = c
这样就找到了方程的一组解(x0 * c / GCD(a, b), y0 * c / GCD(a, b))。
定理二:若GCD(a, b)=1,且x0,y0为a*x + b * y 的一组解,则该方程的任一解可表示为x = x0 + b * t, y = y0 - a * t,对任一整数t都成立。
往往我们要找x的最小整数解,那么 t = b / GCD(a, b), x = (x % t + t) % t;此时x即为最小整数解。
bool TY(int a, int b, int c, int &x, int &y){
int d = exgcd(a, b, x, y);
if(c % d != 0) return 0;
int k = c / d;
x *= k;
y *= k;
return 1;
}//x是全局变量,返回意义不大,为了方便处理无解的情况,把函数设为boo类型。
注意:求最小整数解时加上:
t = b / GCD(a, b),
x = (x % t + t) % t;