一阶线性同余方程
给定 \(a,b,m\) ,求整数 \(x\) ,满足 \(ax\equiv b\ (mod \ m)\)。
这说明 \(ax-b\) 是 \(m\) 的倍数,设为 \(-y\) 倍,这就得到二元线性丢番图方程 \(ax+my=b\) 。
所以,求解一阶线性同余方程等价于二元线性丢番图方程。
定理
设 \(a,b,m\in N\) ,\(m>0\) ,\((a,m)=d\) 。
若 \(d\nmid b\) ,则 \(ax\equiv b\ (mod \ m)\) 无解。
若 \(d\mid b\) ,则 \(ax\equiv b\ (mod \ m)\) 有 \(d\) 个模 \(m\) 不同余的解。
推论
$a $ 和 \(m\) 互质时,因为 \(d=(a,m)=1\) ,所以线性同余方程 \(ax\equiv b\ (mod \ m)\) 有唯一的模 \(m\) 不同余的解。
这条推论在求解同余方程有很重要的作用。先求逆,再用逆求 \(x\) 。
逆
(一)求单个逆
扩展欧几里得
对于 \(ax\equiv1\ (mod \ m)\) ,即丢番图方程 \(ax+my=1\) ,
先用扩展欧几里得算法算出 \(ax+my=1\) 的一个特解 \(x_0\) ,通解 \(x=x_0+mn\) 。
若要求最小整数解,则 \(x=((x_0\ mod \ m) + m)\ mod \ m\) 。
费马小定理
快速幂求逆元 费马小定理 - AKgrid - 博客园
(二)求多个逆
若要求 \(1\sim n\) 模 \(p\) 所有的逆,用递推法。时间复杂度 \(O(n)\) 。
首先,\(i=1\) 时,\(i^{-1} = 1\) 。当 \(i > 1\) 时,
(1)设 \(p/i=k\) ,余数为 \(r\) ,所以 \(k\ \cdot\ i+r\equiv0\ (mod\ p)\);
(2)等式两边同乘 \(i^{-1} \ \cdot\ r^{-1}\) ,得 \(k\ \cdot\ r^{-1} +i^{-1}\equiv 0\ (mod\ p)\);
(3)移项得 \(i^{-1}\equiv-k\ \cdot\ r^{-1}\ (mod\ p)\) ,代入 \(k=p/i\) ,得 \(i^{-1}\equiv-p/i\ \cdot\ r^{-1}\ (mod\ p)\) ;
(4)由于 \(0\equiv p\ (mod \ p)\) ,叠加后得到 \(i^{-1}\equiv(p-p/i)\ \cdot\ r^{-1}\ (mod\ p)\)。
(三)用逆求解同余方程
对于 \(ax\equiv b\ (mod \ m)\),直接两边同时乘 \(a^{-1}\) ,就得到方程的解 \(x\equiv a^{-1}b\ (mod \ m)\)。
其中,\(a\ \cdot\ a^{-1}\equiv 1\ (mod\ m)\),可以利用这一点简单求逆。
例如,\(8x\equiv 22\ (mod\ 31)\) ,两边同时乘以 \(8\) 模 \(31\) 的逆 \(4\) ( \(8 \times 4 \equiv 1 \ (mod \ 31)\) ),得到 \(x\equiv 88\ (mod \ 31)\equiv 26\ (mod \ 31)\)。
[AcWing878] 线性同余方程
题目描述
给定 \(n\) 组数据 \(a_i,b_i,m_i\),对于每组数求出一个 \(x_i\),使其满足 \(a_i \times x_i \equiv b_i \pmod {m_i}\),如果无解则输出 impossible
。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一组数据 \(a_i,b_i,m_i\)。
输出格式
输出共 \(n\) 行,每组数据输出一个整数表示一个满足条件的 \(x_i\),如果无解则输出 impossible
。
每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。
输出答案必须在 \(int\) 范围之内。
数据范围
\(1 \le n \le 10^5\),
\(1 \le a_i,b_i,m_i \le 2 \times 10^9\)
输入样例:
2
2 3 6
4 3 5
输出样例:
impossible
-3
算法
注意结果开 \(long \ long\) 。
C++ 代码
#include<bits/stdc++.h>
using namespace std;
int n, x, y;
using LL = long long ;
int exgcd(int a, int b, int &x, int &y)
{if (!b){x = 1, y = 0;return a;}int x1, y1;int d = exgcd(b, a % b, x1, y1);x = y1, y = x1 - a / b * y1;return d;
}int main()
{cin >> n;while (n --){int a, b, m;cin >> a >> b >> m;int d = exgcd(a, m, x, y);if (b % d) puts("impossible");else {x = (LL)x * b / d % m;cout << x << endl;}}return 0;
}
P3811 【模板】模意义下的乘法逆元
题目背景
这是一道模板题
题目描述
给定 \(n,p\) 求 \(1\sim n\) 中所有整数在模 \(p\) 意义下的乘法逆元。
这里 \(a\) 模 \(p\) 的乘法逆元定义为 \(ax\equiv1\pmod p\) 的解。
输入格式
一行两个正整数 \(n,p\)。
输出格式
输出 \(n\) 行,第 \(i\) 行表示 \(i\) 在模 \(p\) 下的乘法逆元。
输入输出样例 #1
输入 #1
10 13
输出 #1
1
7
9
10
8
11
2
5
3
4
说明/提示
$ 1 \leq n \leq 3 \times 10 ^ 6\(,\)n < p < 20000528 $。
输入保证 $ p $ 为质数。
算法
模版题,线性求多个逆元。
代码
#include <iostream>
using namespace std;const int N = 3e6 + 10;
long inv[N];int main() {int n, p;scanf("%d%d", &n, &p);inv[1] = 1;puts("1");for (int i = 2; i <= n; i++)printf("%ld\n", inv[i] = (long)p - (p / i) * inv[p % i] % p);
}