1. 程式人生 > 實用技巧 >同餘方程 【程式碼】

同餘方程 【程式碼】

此文包含:

  • 線性同餘方程
  • 線性同餘方程組
  • 高次同餘方程(未完成)

詳見程式碼註釋。

感覺英文和程式碼合起來比較好看,於是程式碼註釋就幾乎只有英文了。

/*
同餘方程系列三合一 

2021.01.02 - 2021.xx.xx

Author: zimujun 
*/

/*
Content

exgcd

線性同餘方程

線性同餘方程組 

高次同餘方程
*/

#include <bits/stdc++.h>
#define LL long long

namespace Basic {
	template <typename Temp> inline void read(Temp & res) {
		Temp fh = 1; res = 0; char ch = getchar();
		for(; !isdigit(ch); ch = getchar()) if(ch == '-') fh = -1;
		for(; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ '0');
		res = res * fh;
	}
	template <typename Temp> inline void Checkmax(Temp & num, Temp comp) {if(comp > num) num = comp;}
	template <typename Temp> inline void Checkmin(Temp & num, Temp comp) {if(comp < num) num = comp;}
}
using namespace Basic;

namespace Math {
	template <typename Temp> inline Temp gcd_(Temp A, Temp B) {Temp C; while(B) C = B, B = A % B, A = C; return A;}
	template <typename Temp> inline Temp lcm_(Temp A, Temp B) {return A / gcd_<Temp>(A, B) * B;}
	/*
	The gcd function below is a tool which can be used to solve many questions.
	*/
	template <typename Temp> Temp gcd(Temp A, Temp B, Temp & X, Temp & Y) {
		if(B == 0) {X = 1; Y = 0; return A;}
		LL res = gcd(B, A % B, X, Y);
		LL Z = Y; Y = X - A / B * Y; X = Z;
		return res;
	}
}

namespace equation {
	/*
	Description: This is a function to solve an congruence equation.
	Algorithm used: Euclid Algorithm (gcd)
	Step:
		1. Equation ax = b (mod m) turns into ax + (-y)m = b;
		2. Use Euclid algorithm to get an solution to this equation; 
		3. Calculate x = x_0 * (b / gcd(a, m)) then one of the solution to this equation is x, all solutions is x + tm.
	*/
	template <typename Temp> inline void solve(Temp A, Temp B, Temp M, Temp & X) {
		Temp D = Math::gcd_<Temp>(A, M);
		if(B % D) {X = -1; return;}
		Temp Y; D = Math::gcd<Temp>(A, M, X, Y);
		X = B / D * X;
		X = (X % M + M) % M;
	}
}

namespace equationset {
	/*
	Description: This is a funtion to solve a congruence equation set
	Algorithms used: exCRT
	Steps:
		1. Solve the first congruence equation;
		2. Calculate the lcm of the first k modulus, named M;
		3. If the first k equations' solution is x, then (x + tM)(s) are all solutions of them. So make another equation and solve it;
		4. Repeat 2. and 3. until k equals to n. 
	*/
	template <typename Temp> inline void solve(int number, Temp A[], Temp B[], Temp M[], Temp & X) {
		if(number >= 1) equation::solve(A[1], B[1], M[1], X); Temp Ms = M[1]; if(X == -1) return;
		for(register int i = 2; i <= number; ++i) {
			Temp tA = A[i] * Ms, tB = B[i] - A[i] * X, tM = M[i];
			tB = (tB % tM + tM) % tM; Temp resT;
			equation::solve(tA, tB, tM, resT); 
			if(resT == -1) return; X += resT * Ms;
			Ms = Math::lcm_<Temp>(Ms, M[i]);
			X = (X % Ms + Ms) % Ms; 
		}
	}
}

namespace HDCE {
	/*
	This is a function to solve higher degree congruence equation,
	Algorithms used:BSGS(Baby_Step_Giant_Step)
	*/
}