1. 程式人生 > >HDU 1573 模線性方程

HDU 1573 模線性方程

沒有 sca 點擊 scanf can small name round target

給定模線性方程組,求最終的值的通解。點擊

兩個模方程可以化解成一個模方程

x mod a1 = b1

x mod a2 = b2

a1*k1 + a2*k2 = b2 – b1 // 其中k1k2是自由元

用擴展歐幾裏得算出k1的解,當然它是一個解系,找出最小k1作為特解,帶入x = a1 * k1 + b1得到x

然後把這個x當作特解,記作x1.

之前k1本來是一個解系,他的模是a2/gcd(a1,a2),[簡單將gcd(a1,a2)記作t], 也就是說k1如果作為一個解系的話,k1 = a2/t * x + k0

其中x是任意整數,k0是一個特解。

將求到的k1代入到x = a1 * k1 + b1 中,得到的是一個x的解系,如果用上邊的特解x0表示,就是x = x0 + a1*a2/t;

得到一個新的模方程 x mod a1*a2/t = x0 ,這個方程繼承上面兩個方程的特性,所以兩者之間是等價的。

這樣將兩個兩個方程消掉,最後只剩下一個方程,最後的解系就是最終的x的解系。如果中間出現歐幾裏得算不出來解,那麽說明這個方程組沒有解。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e6 + 500;

void extend_gcd(LL a, LL b, LL &x, LL &y, LL &d)
{
    
if(b == 0) { x = 1; y = 0; d = a; } else { extend_gcd(b, a%b, y, x, d); y -= (a/b) * x; } } int T,n,m; LL a[20],b[20]; int main() { scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); for(int i = 0; i < m; i++) scanf(
"%d", &a[i]); for(int j = 0; j < m; j++) scanf("%d", &b[j]); LL flag = 0; LL x, y, d; LL m1 = a[0], r1 = b[0]; LL m2, r2; LL c, t; for(int i = 1; i < m; i++) { m2 = a[i], r2 = b[i]; extend_gcd(m1, m2, x, y, d);//d = gcd(m1,m2) m1*x + m2*y = gcd(m1,m2) c = r2 - r1; if(c % d) { flag = 1; break; } t = m2 / d; // m1*(x+m2/d*k1) + m2*(y + m1/d*k2) = m1*x + m2*y + (m1*m2/d * k1 + m2*m1/d*k2) = gcd(m1,m2) x = (((x * c / d) % t) + t) % t; r1 = m1*x + r1; m1 = m1*m2/d; r1 %= m1; } int ans = 0; if(flag || r1 > n) { printf("0\n"); } else { int ans = (n - r1) / m1 + 1; if(r1 == 0) ans--; printf("%d\n", ans); } } return 0; }

HDU 1573 模線性方程