线性同余方程
// 定理一:对于方程a * x + b * y = c 有整数解 x, y 可以转化为a * x 三 c(mod b) // 根据扩展欧几里得算法可知,a * x0 + b * y0 = GCD( a, b)一定有解, 此时将方程左右同时出去GCD( a, b)在乘上c // 方程就转化成了a * x0 * c / GCD( a, b) + b * y0 * c / GCD( a, b) = c 已经可以说明 c / GCD( a, b)是整数了 // 可以知道 b * y mod b == 0,则 c mod b = (a * x + b * y) mod b 就等于a * x mod b // 所以上面两个方程是等价的, 而同理可知 b * y 三 c (mod a) 此时说明 c 一定是a 与 b是最大公约数的倍数(包括 0倍) // 定理二:若GCD( a, b) = 1, 且x0, y0为a * x0 + b * y0 = c 的一组解,那么x = x0 + b * t, y = y0 + a * t 都是原来方程的解 // (t 是整数). 所以能从此处知道方程存在的最小整数解为 t = b / GCD( a, b), x = ((x % t) + t) % t (此处加t 是为了防止取模后为负数) // 先来扩展欧几里得算法 // 过程证明 // 扩展欧几里得算法 // 方程形式 a * x0 + b * y0 = GCD( a, b); // 需要求解出 x0与y0 // 现在考虑最后状态 是 a` * 1 + 0 * y0 = GCD( a, b); // 此时的 a`就是GCD( a, b) // 然后根据a * x0 + b * y0 = GCD( a, b) = GCD( b, a % b) = b * x0` + (a % b) * y0` = b * x0` + (a - a / b * b) * y0` // 整理得出: GCD( a, b) = y0` * a + (x0` - a / b * y0`) * b 化成这种形式后可以看出(看了好长时间...tcl) // a * x0 + b * y0 = a * y0` + b * (x0` - a / b * y0`) * b 所以可以根据此方程算出x0和y0 可以由 a与b还有上次的 x0` 与 y0`算出 int k_GCD(int a,int b,int &x,int &y){ if(b == 0){ x = 1; y = 0; return a; } int d = k_GCD(b,a % b,x,y);//在递归后返回的x与y在这还是上次的x与y int temp = x; x = y; y = temp - a / b * y; //经过计算 x 与 y已经经过上面写的对应关系转化成了满足当前方程的x 与 y(方程就是a * x + b * y = GCD(a,b)) return d; }
1 // 下面开始理解线性同余方程里最小整数解 2 // 根据上面知道同余方程可以化简成a * x + b * y = c 的形式 3 // 观察 a * x + b * y = c 与 a * x0 + b * y0 = GCD( a, b) 的形式,不难看出这两个方程很像 4 // 所以根据扩展欧几里得算出的两个x0与y0就够用来算出线性同余方程的x与y 5 // 具体的对应关系是:x = x0 * (c / GCD( a, b)),y = y0 * (c / GCD( a, b)) 6 // 根据定理二我们知道但GCD( a, b) = 1 时方程的所有解是可以写成 x = x0 + b * t,y = y0 + a * t 7 // 这是进行一个小变形也就是 (a / GCD( a, b)) * x0 + (b / GCD( a, b)) * y0 = 1 8 // 然后写出解系 x = x0 + (b / GCD( a, b)) * t, y = y0 + (a / GCD( a, b)) * t 9 // 令k = b / GCD( a, b) 10 // 从这里能够发现 x 会加上(b / GCD( a, b))的任意整数倍,那么最小的正整数解就是(x0 % k + k) % k 这里加k是为了防止出现负数的请况 11 // 到此证明结束 12 // 开始写程序 13 14 int k_gcd(int a,int b,int &x,int &y){ 15 if(!b){ 16 x = 1; 17 y = 0; 18 return a; 19 } 20 int d = k_gcd(b,a % b,x,y); 21 int temp = x; 22 x = y; 23 y = temp - a / b * y; 24 return d; 25 } 26 27 void test(int b,int d,int x){ 28 int k = b / d; 29 return (x % k + k) % k;//返回的就是最小正整数解 30 }