##[$AcWing$ $878$. 线性同余方程](https://www.acwing.com/problem/content/description/880/)
### 一、题目描述
给定 $n$ 组数据 $a_i,b_i,m_i$,对于每组数求出一个 $x_i$,使其满足 $a_i×x_i≡b_i(mod \ m_i)$,如果无解则输出 `impossible`。
**输入格式**
第一行包含整数 $n$。
接下来 $n$ 行,每行包含一组数据 $a_i,b_i,m_i$。
**输出格式**
输出共 $n$ 行,每组数据输出一个整数表示一个满足条件的 $x_i$,如果无解则输出 `impossible`。
每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。
输出答案必须在 $int$ 范围之内。
**数据范围**
$1≤n≤10^5,1≤a_i,b_i,mi≤2×10^9$
**输入样例:**
```cpp {.line-numbers}
2
2 3 6
4 3 5
```
**输出样例:**
```cpp {.line-numbers}
impossible
-3
```
### 二、线性同余方程
**【扩展欧几里得算法的一个典型应用】**
$ax\equiv\ b(mod\ m)$
**举个栗子**:
$2x \equiv 3 (mod\ 6)$
---
$x=1,2x=2,2\%6=2$
$x=2,2x=4,4\%6=4$
$x=3,2x=6,6\%6=0$
---
$x=4,2x=8,8\%6=2$
$x=5,2x=10,10\%6=4$
$x=6,2x=12,12\%6=0$
---
...
余数开始循环了,一直都是$2,4,0$...
不会产生$3$这个余数,所以,无解。
**再来一个栗子:**
$4x\equiv\ 3 (mod\ 5)$
$x=1,4x=4, 4\%5 =4$
$x=2,4x=8, 8\%5 =3$
$x=3,4x=12, 12\%5 =2$
$x=4,4x=16, 16\%5 =1$
$x=5,4x=20, 20\%5 =0$
---
$x=6,4x=24, 24\%5 =4$
$x=7,4x=28, 28\%5 =3$
$x=8,4x=32, 32\%5 =2$
$x=9,4x=36, 36\%5 =1$
$x=10,4x=40, 40\%5 =0$
---
....
所以有解,其它第一个解是 $x=2$,第二个解是$7$。
这两个解之间差了一个$5$,即$2+5=7$,每加一个$5$,都可以得到一个解。比如 $7+5=12$也是一个解。
#### 2、为什么线性同余方程可以使用欧几里得算法来求解呢?
- $a∗x\equiv b (mod\ m)$ **表示意义** 是$(a*x) \% m=b$,从而$(a∗x−b)\%m=0$ 。
假设是$y_1$倍,因此线性同余方程转化为 $a∗x-b=m∗y_1$ , 移项: $a*x-m*y_1=b$。令 $-y_1=y$ ,则: $a * x + m * y = b$ ,这就是一个标准的二元一次方程。
- 根据贝祖定理,上述等式有解当且仅当 $gcd(a,m)|b$,也就是$b$是$gcd(a,m)$的整数倍,有解;
如果$b$不是$gcd(a,m)$的整数倍,无解,输出 `impossible`
- 用扩展欧几里得求出一组特解 $x_0$,$y_0$, 使得 $a∗x_0+m∗y_0=gcd(a,m)$。
- 对比两个方程:扩展欧几里得公式和线性同余方程两个东东
$
\large \left\{\begin{matrix}
a*x + m*y = b & \\
a∗x_0+m∗y_0=gcd(a,m) &
\end{matrix}\right.
$
两个方程的左右两边,左边的系数是一样的$a,m$,右边的常数不一样,一个是$b$,另一个是$gcd(a,m)$,我们刚才上面讨论过,$b$必须是$gcd(a,m)$的整数倍,方程才有解,也就是说,现在$b$一定是$gcd(a,m)$的整数倍!
设 $d=gcd(a,m)$,那么$b=t*d$,其中$t=b/gcd(a,m)$是一个整数。
$\therefore x=b/gcd(a,m) * x_0$,
因为害怕在乘法运算过程中,造成爆$int$,所以,出发前对$b$进行了转$long\ long$操作,以保证不爆$int$.同时,因为是同余方程,如果取得的值大于$m$,还需要模一下$m$.即:
```c++
(LL) b / d * x % m
```
### 三、实现代码
```cpp {.line-numbers}
#include
using namespace std;
typedef long long LL;
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main() {
int n;
cin >> n;
while (n--) {
int a, b, m;
cin >> a >> b >> m;
int x, y;
int d = exgcd(a, m, x, y);
if (b % d)
puts("impossible");
else
printf("%d\n", (LL)b / d * x % m);
}
return 0;
}
```