#include <iostream>
using namespace std;
typedef long long LL;
/* ax + by = gcd(a, b) */
/* x = xpp - q * xp */
/* y = ypp - q * yp */
/* xpp 表示 x pre pre, 即x(n - 2), 其余同理 */
template <class T>
T ex_gcd(T a, T b, T &x, T &y) {
T xpp, xp;
T ypp, yp;
T r = a % b, q = a / b;
if (!r) {
x = 0, y = 1;
return b;
}
xpp = 0, ypp = 1;
x = xp = 1, y = yp = -q;
while (true) {
a = b;
b = r;
q = a / b, r = a % b;
if (!r) return b;
x = xpp - q * xp, y = ypp - q * yp;
xpp = xp, ypp = yp;
xp = x, yp = y;
}
}
// 介于(0, mod]的最小模mod同余整数
template <class T>
T toPositive(T x, T mod) {
x = ((x % mod) + mod) % mod;
return x ? x : mod;
}
// 介于[-mod, 0)的最大模mod同余整数
template <class T>
T toNegative(T x, T mod) {
x = ((x % mod) - mod) % mod;
return x ? x : -mod;
}
// EVERY表示任意值都是解, NIL表示无解
enum {EVERY = -2, NIL = -1};
// 求解形如ax = b (mod c)的Linear Congruence Equaltion(线性同余方程)
// 使用ex_gcd求解ax + cy = b
LL linearCongruence(LL a, LL b, LL c) {
a = toPositive(a, c) % c;
b = toPositive(b, c) % c;
// if (!a && !b) return EVERY;
if ((!a && b) || !c) return NIL;
// else if (a && !b) return 0;
// 当a小于0时, 将符号交给x, 此时xnf为真
// 表示x Negative Flag
bool xnf = false, ynf = false;
if (a < 0) xnf = true, a = -a;
if (c < 0) ynf = true, c = -c;
b = toPositive(b, c);
// g = gcd(a, c)
LL x, y, g;
g = ex_gcd(a, c, x, y);
if (b % g) return NIL;
if (xnf) {
x = toNegative(x, c / g);
x = -x;
} else {
x = toPositive(x, c / g);
}
// b此时一定能被g整除
// 括号在一定程度上防止因为极端数据导致溢出
// 对c取模得到[0, c / g - 1]之间解,即最小正数解
return x * (b / g) % (c / g);
}
依赖:
-扩展欧几里得
-得到(0, mod]之间最小同余整数
-得到[-mod, 0)之间最大同余整数