解一元线性同余方程组

定义

a, b是整数,m是正整数,形如ax≡ b(mod m),且x是未知整数的同余式称为一元线性同余方程。

对于ax ≡ b (mod m),可以变形为 ax = b + my,在变形一下就是ax+my = b。这样就把一个一元线性同余方程给转换为可以使用拓展欧几里德求解的形式了。(什么,你和我说你拓展欧几里德都不知道?衰仔,点这里)

深入

那今天的重点来了,什么是一元线性同余方程组呢?
就是如下这样的一堆一元线性同余方程放在一起让你求x。
X ≡ r1 (mod a1)
X ≡ r2 (mod a2)
X ≡ r3 (mod a3)
.
.
.
X ≡ rn (mod an)

那对于这样一个方程组,首先我们先对先两个式子进行变换得到
X = r1 + a1y1
X = r2 + a2y2
两个式子相减后得到 r1 + a1y1 = r2 + a2y2
变换一下得到,a1y1 - a2y2 = r2 - r1
设a = a1
b = a2
c = r2 - r1
x = y1
y = y2
方程变换成了ax + by = c
然后通过拓展欧几里德进行求能够求出来x,将x也就是y1回带回去得到一个特解X值(X = r1 + a1 y1)。易得通解X’ = X + k*lcm(a, b),上面式子通过变换能写为 X’ mod lcm(a, b) = X 同余式子就是X’ = X (mod lcm(a, b)) 这样就把前两个式子联立起来了,然后再继续向下进行下去,直到最后化成一个式子就剩下X’ = X (mod lcm(a1, a2…an))。X即为最小的正整数解。

例题

poj3891

模板题没啥说的

#include 

using namespace std;
typedef long long ll;

void exgcd(ll a, ll b, ll &gcd, ll &x, ll &y)
{
	if (!b)
	{
		gcd = a;
		x = 1;
		y = 0;
	}
	else
	{
		exgcd(b, a%b, gcd, y, x);
		y-=(a/b)*x;
	}
}

int main()
{
	ll n;
	
	while (scanf("%lld", &n) != EOF)
	{
		ll a1, r1, a2, r2, a, b, c, d, x0, y0;
		bool flag = true;
		
		scanf("%lld %lld", &a1, &r1);
	
		for (int i=0; i<n-1; i++)
		{
			scanf("%lld %lld", &a2, &r2);
			
			a = a1, b = a2, c = r2-r1;
			exgcd(a, b, d, x0, y0);
			
			if (c%d != 0)
			{
				flag = false;
			}
			
			int t = b/d;
			x0 = (x0*(c/d)%t+t) % t;
			r1 = a1*x0+r1;
			a1 = a1*(a2/d);
		}
		
		if (flag)
		{
			printf("%lld\n", r1);
		}
		else
		{
			printf("-1\n");
		}
	}
	
	return 0;
} 

你可能感兴趣的:(笔记)