同余相关
xiejinhao
2019-07-06 13:57:42
# 同余
- **定义**
$ \ \ \ \ \ \ \ \ $ 若整数$a$和整数$b$除以正整数$m$的余数相等,则称$a,b$模$m$同余,记为$a \equiv b \pmod m$。
- **相关性质:**
1. $a \equiv a \pmod m$。
1. 若$ \ a \equiv b \pmod m$,则$ \ b \equiv a \pmod m$。
1. 若$ \ a \equiv b \pmod m,\ \ b \equiv c \pmod m \ $则$ \ a \equiv c \pmod m$。
1. 若$ \ a \equiv b \pmod m, \ c \equiv d \pmod m \ $,则$ \ a±c \equiv b±d \pmod m$。
1. 若$ \ a \equiv b \pmod m, \ c \equiv d \pmod m \ $,则$ \ ac \equiv bd \pmod m$。
1. 若$ \ ac \equiv bc \pmod m, \ c≠0$,则$ \ a \equiv b \pmod {m/gcd(c,m)}$;当$c,m$互质时,即$gcd(c,m)=1$,有$ \ a \equiv b \pmod m$。
1. 若$ \ a \equiv b \pmod m \ $,则$ \ a^n \equiv b^n \pmod m$。
1. 若$ \ a \equiv b \pmod {m_i}, \ i=1,2,…,n \ $,则$ \ a \equiv b \pmod {lcm(m_1,m_2,…,m_n)}$。特别的,若 $m_1,m_2,…,m_n$ 互质,则$a\equiv b \pmod{\prod \limits _{i=1}^{n}m_i}$。
- **同余类与剩余系:**
$ \ \ \ \ \ \ \ \ $ 对于$∀a∈[0,m-1]$,集合$\{a+km\}(k∈Z)$的所有数模$m$同余,余数都是$a$,则称该集合为一个模$m$的同余类,记为$\ \bar{a}$。
$ \ \ \ \ \ \ \ \ $ 模$m$的同余类一共有$m$个,分别记为$\bar{0}, \ \bar{1}, \ \bar{2},…,\bar{m-1}$。它们构成$\ m \ $的完全剩余系。
$ \ \ \ \ \ \ \ \ $ $1-m$中与$ \ m \ $互质的数代表的同余类共有$φ(m)$个,他们构成$ \ m \ $的简化剩余系。
- **费马小定理:**
$ \ \ \ \ \ \ \ \ $ 若$\ p \ $是质数,则对于任意整数$a$,有$a^p \equiv a \pmod m$。
- **欧拉定理:**
$ \ \ \ \ \ \ \ \ $ 若正整数$ \ a,n \ $互质,则$ \ a^{φ(n)} \equiv 1 \pmod n$
- **※欧拉定理相关:**
$ \ \ \ \ \ \ \ \ $ 若正整数$ \ a,n \ $互质,则对于任意正整数$ \ b \ $,有$ \ a^{b} \equiv a^{b \mod φ(n)} \pmod n$
- **威尔逊定理:**
$ \ \ \ \ \ \ \ \ $当且仅当$p$为质数时,$(p-1)!\equiv -1\pmod p$。
------------
同余相关 | 扩展欧几里得算法(扩欧)
------------
- $Bézout$ **定理:**
$ \ \ \ \ \ \ \ \ $ 对于任意整数$a,b$,存在一对整数$x,y$,满足 $ax+by=gcd(a,b)$。
$ \ \ \ \ $**证明:**
1. 在欧几里得算法的最后一步,有$b=0$,一定存在一对整数$x=1,y=0$,满足$a*1+0*0=gcd(a,0)=a$。
1. 若$b>0$,则$ \ gcd(a,b)=gcd(b,a\mod b)$。假设存在一对整数$ \ x,y$,满足$ \ bx+ (a \mod b)y=gcd(b,a \mod b)$,则$ \ bx+(a \mod b)y=bx+(a-b$⌊$a/b$⌋$)y=ay+b(x-$⌊$a/b$⌋$y)$。
1. 令$x_{'}=y,y_{'}=x-$⌊$a/b$⌋$y$,则$ax_{'}+by_{'}=gcd(a,b)$.
$ \ \ \ \ $对欧几里得算法运用数学归纳法,则 **$Bézout$ 定理** 成立。
$ \ \ \ \ $**证毕。**
由于 **$Bézout$ 定理**是按欧几里得算法证明的,上述证明又给出了计算上述方程的一组特解$x,y$的方法。这就是**扩展欧几里得算法**。
```cpp
int exgcd(int a, int b, int &x, int &y) {
if(b == 0) {x = 1, y = 0; return a;}
int d = exgcd(b, a%b, x, y);
int z = x; x = y, y = z - y * (a / b);
return d;
}
```
上述算法在范围$a,b$的最大公约数的同是,求出了一组特解$x_0,y_0$。
对于$ax+by=c$,其有整数解当且仅当$d|c$。我们可以利用上述算法先求出$ax+by=d$的一组特解$x_0,y_0$,然后同时将$x_0,y_0$同时乘上$\frac{c}{d}$,就得到了方程$ax+by=c,d|c$的一组特解。
方程$ax+by=c$的通解可以表示为:
$$x=\frac{c}{d}x_0+k\frac{b}{d}, \ \ \ \ y=\frac{c}{d}y_0+k\frac{a}{d}, \ \ \ k∈Z,d=gcd(a,b)$$
- **乘法逆元:**
$ \ \ \ \ $若整数$b,m$互质,并且$b|a$,则此存在一个整数$x$,使得$a/b \equiv ax \pmod m$。我们把$x$叫做$b$模$m$的乘法逆元,记作$b^{-1}\pmod m$。
上面那段定义来自于《算法竞赛进阶指南》,其实可以简述为存在一个$x$,使互质的$b,m$两个整数满足 $b*x \equiv 1 \pmod m $,其算式等价于$bx=km+1,\ \ \ b,k,m,x∈Z$,求$k,x$。
若$m∈prime$,根据费马小定理:$b^{m-1}\equiv1\pmod m$,则有$b*b^{m-2}\equiv1\pmod m$,此时$b^{m-2}$即为$b$模$m$的乘法逆元。
**乘法逆元的应用:**
对于第一个定义,题目要求取模运算时,一般会给定一个质数$p$,当然不是也不要紧,在处理$a/b \mod p$这样的式子时,保证$b,p$互质,则有且仅有一个$x$满足$a/b \mod p=a*x \mod p$,这时,$a/b \mod p=(a \mod p)(x \mod p)\mod p$ 。
------------
同余方程
------------
### **1.线性同余方程**
线性同余方程形如$ax \equiv b \pmod m$,求整数$x$或输出无解,这一类同余方程的指数为1,称为一次同余方程,也称线性同余方程。
上述方程等价于$ax-b \mod m =0$,不妨设$ax-b=-ym$,则有$ax+ym=b$,根据扩展欧几里得,我们可以求出方程$ax+ym=gcd(a,b)=d$的一组特解$x_0,y_0$。
根据 **$Bézout$ 定理**,方程有解当且仅当$gcd(a,m)|b$。
上面提到了这一类方程的解法,求出特解$x_0$后,方程的一个特解$x=x_0*\frac{b}{d}$。
**方程通解**:所有模$m/gcd(a,m)$与$x_0$同余的整数,表示为$X_i \equiv x_0 \pmod{m/gcd(a,m)}, \ \ \ i=1,2,…$。
- **例题**:[**P1082 同余方程**](https://www.luogu.org/problemnew/show/P1082)
由上述知识可得$ax \equiv 1\pmod b$可变为$ax+by=1$,利用欧几里得算法可以解出一组特解$x_0,y_0$,而$x_0$就是原方程的一个解,根据方程通解,利用模运算找到$[1,b]$的整数$x$,就是最小正整数解。
```cpp
//部分代码如下
typedef long long ll;
int exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) {x = 1, y = 0; return a;}
ll d = exgcd(b, a%b, x, y);
ll z = x; x = y, y = z - y * (a / b);
return d;
}
int main() {
ll a, b, x=0, y=0;
scanf("%lld %lld", &a, &b);
exgcd(a, b, x, y);
printf("%lld\n",(x % b + b) % b);
}
```
- **中国剩余定理($CRT$)**
$ \ \ \ \ \ \ \ $设$m_1,m_2,…,m_n$是两两互质的整数,$m=\prod_{i=1}^{n}m_i, \ \ M_i=m/m_i, \ \ t_i$是线性同余方程$M_it_i\equiv 1 \pmod {m_i}$的一个解。对于任意的$n$个整数$a_1,a_2,…,a_n$,方程组
$$\begin{cases} { \ x \equiv a_1\pmod {m_1}} \\\ {x \equiv a_2\pmod {m_2}} \\\ {\ \ \ \ \ \ \ \ \ \ \ ...}\\\ {x \equiv a_n\pmod{m_n}} \end{cases}$$
$ \ \ \ \ \ \ \ $有整数解,解为$ \ x=\sum_{i=1}^{n}a_iM_it_i$。
$ \ \ \ \ \ \ \ $我们已经会解形如$ax \equiv 1\pmod m$的线性同余方程,因此,我们可以求解出$M_it_i\equiv 1 \pmod m$中的最小非负整数$t_i$,而方程的通解则为$x + i * M, \ \ \ i∈Z$。
```cpp
#include<cstdio>
using namespace std;
const int SIZE = 110;
int n, M = 1, a[SIZE], m[SIZE];
void exgcd(int a, int b ,int &x, int &y) {
if(b == 0) { x = 1, y = 0; return; }
exgcd(b, a % b, x, y);
int z = x; x = y, y = z - y * (a / b);
}
int CRT() {
int sum = 0;
for(int i = 1; i <= n; i++) M *= m[i];
for(int i = 1; i <= n; i++) {
int Mi = M / m[i];
int ti = 0, y = 0;
exgcd(Mi, m[i], ti, y);
ti = (ti % m[i] + m[i]) % m[i];
sum = (sum + a[i] * Mi * ti) % M;
}
return (sum + M) % M;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d %d", &a[i], &m[i]);
printf("%d", CRT());
return 0;
}
```
$ \ \ \ \ \ \ \ $上面程序解出方程组的最小非负整数解。
- **扩展中国剩余定理($EXCRT$)**
$ \ \ \ \ \ \ \ $由基础的$CRT$我们已经会求解上述方程组。现在,由于方程组:
$$\begin{cases} { \ x \equiv a_1\pmod {m_1}} \\\ {x \equiv a_2\pmod {m_2}} \\\ {\ \ \ \ \ \ \ \ \ \ \ ...}\\\ {x \equiv a_n\pmod{m_n}} \end{cases}$$
$ \ \ \ \ \ \ \ $其中$m_1,m_2,…,m_n$为**不一定两两互质的整数**,求$x$的最小非负整数解。
$ \ \ \ \ \ \ \ $与$CRT$不同的是,这里的 $m_i$ 不一定两两互质。
$ \ \ \ \ \ \ \ $设前 $n - 1$个方程的一个解为 $x$,令$M=\prod_{i =1}^{n-1}m_i$,则前 $n-1$ 个方程的通解为 $x +i*M , \ \ \ i∈Z$。
$ \ \ \ \ \ \ \ $则对于整个方程组,就是要求解一个整数$k$使得$x + k*M\equiv a_n\pmod {m_n}$
$ \ \ \ \ \ \ \ $上述式子可转化为$k*M \equiv a_n-x\pmod{m_n}$,这也是我们熟悉的形如$ax\equiv b\pmod m$的线性同余方程,则上述方程有解,当且仅当$gcd(M,m_n) \mid (a_n-x)$,解为$k$。我们仍可以利用扩展欧几里得算法求解方程,则方程组的解就是$x+k*M$。
$ \ \ \ \ \ \ \ $因此,我们只需要使用$n$次扩展欧几里得算法,就可以求出整个方程的最小正整数解。
```cpp
#include<cstdio>
using namespace std;
const int SIZE = 1e5 + 10;
typedef long long ll;
typedef long double ld;
ll a[SIZE], m[SIZE];
ll quick_mul(ll x, ll y, ll p) { //x * y mod p
return
(x * y - (ll)((ld)x / p * y) * p + p) % p;
}
//由于这里需要用到gcd来判断是否有界,故需要返回值
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) { x = 1, y = 0; return a;}
ll d = exgcd(b, a % b, x, y);
ll z = x; x = y, y = z - y * (a / b);
return d;
}
ll EXCRT(int n) {
ll M = m[1], ans = a[1]; //x ≡ a[i] (mod m[i])
for(int i = 2; i <= n; i++) {
ll s = ((a[i] - ans) % m[i] + m[i]) % m[i];
//s = a[i] - x
ll x = 0, y = 0, d = exgcd(M, m[i], x, y);
// M*x ≡ 1 (mod m[i]),x相当于要求的k
if(s % d) return -1; //无解
x = quick_mul(x, s / d, m[i] / d);
ans += x * M;
M *= m[i]/d;
ans = (ans % M + M) % M;
//利用模性质,求最正整数小解
}
return (ans % M + M) % M;//返回最小正整数解
}
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%lld %lld", a + i, m + i);
printf("%lld", EXCRT(n));
return 0;
}
```
------------
### **2.非线性同余方程 | 高次同余方程**
$ \ \ \ \ $ **①形如$x^a \equiv b \pmod m$的一类方程**
为什么现讲这一类?因为这一类是急需补充的知识,在一些算法书上基本没有。
那么,要解这一类方程,我们需要知道下面几个知识点:
- **阶:**
设$a,m∈Z, \ \ gcd(a,m) = 1$,则使方程$a^r \equiv 1 \pmod m$ 成立的最小正整数$ \ r \ $称为$a$对模$m$的阶,记为$r=ord_m(a)$,也记为$ \ δ_m(a)$。
**阶的基本性质:**
1. $a^n \equiv 1 \pmod m$的充要条件是$ \ δ_m(a) \ | \ n$
$ \ \ \ \ \ \ \ \ \ \ \ $ **推论**:$δ_m(a)|φ(m)$
**※** **若$δ_m(a)=φ(m)$,则称$a$是模$m$的原根(或写作元根)。**
2. 若 $a \equiv b \pmod m, \ \ gcd(a,m)=1$,则$δ_m(a)=δ_m(b)$。
1. 若 $a^x \equiv a^b \pmod m, \ \ gcd(a,m)=1$,则$x \equiv y \pmod {δ_m(a)}$。
1. 记$n=δ_m(a)$,则$a^1,a^2,…,a^{n-1}$模$m$两两不同余。
1. 若 $a^{-1}a \equiv 1\pmod m$,则$δ_m(a)=δ_m(a^{-1})$。
1. 记$n=δ_m(a), \ \ i=1,2,…, \ \ δ_m(a^i)=S$,则$S=n/gcd(i,n)$。
1. 若 $n \ | \ m$,则对于$∀a∈Z, \ \ \ δ_n(a) \ | \ δ_m(a)$。
1. 若$gcd(m,n)=1, \ gcd(a,mn)=1$,则$δ_{mn}(a)=[ δ_m(a),δ_n(a) ]$。
1. 若$gcd(ab,m)=1, \ gcd(δ_m(a),δ_m(b))=1$,则$δ_m(ab)=δ_m(a)*δ_m(b)$。
- **原根**
原根的定义在上面已经阐明,下面主要看**原根的性质:**
1. 只有$2,4,p^k,2p^k$有原根,其中$p$为奇素数,$k∈N^*$。
1. 一个数$x$若存在原根,则它有$φ(φ(x))$个原根。
1. 记$n=δ_m(a)$,当$n$为原根时,$\bar{a^0},\bar {a^1},\bar{a^2},…,\overline {a^{n-1}}$构成模$n$的简化剩余系。当$n$是质数时$\bar{a^0},\bar {a^1},\bar{a^2},…,\overline {a^{n-1}}$对$n$取模对应的值为{$1,2,…,n-1$}。
- **指标**
设$g$为$n$的一个原根,且$gcd(a,n)=1,a∈Z$,则存在唯一整数$x$使得$g^x \equiv a \pmod n$成立,我们称$x$为$g$为底模$n$的一个指标,记为$x=ind_g(a)$
一般求解上述方程,求出的是解的个数和解的和,这一类问题已经超出我们讨论的范围,对于这一类方程就拓展到这里,读者可以自行查阅相关资料深入探究。
------------
$ \ \ \ \ $ **②形如$a^x \equiv b \pmod m$的一类方程**
问题:
$ \ \ \ \ $ 给定整数$a,b,p$,($p$相当于原方程的$m$),$gcd(a,p)=1$,求非负整数$x$,使得原方程成立。
- **$BSGS$算法**
1. 设 $x=i*t-j, \ t=$⌈$\sqrt p$⌉,$0≤j≤t-1$,则原方程化为$a^{i*t-j }\equiv b \pmod p$,即$a^{t*i} \equiv b*a^j \pmod p$。
1. 对于所有$j∈[0,t-1]$,把$b*a^j\mod p$插入一个$Hash$表。
1. 枚举所有$i$可能的取值,($i∈[0,t]$),求出$a^{t*i}\mod p$,在$Hash$表中查找是否存在对应的$j$,更新答案即可。
```cpp
#include<bits/stdc++.h>
using namespace std;
int power(int a, int x, int p) {
int ans = 1;
while(x) {
if(x & 1) ans = ans * a % p;
x >>= 1, a = a * a % p;
}
return ans;
}
int BGBS(int a, int b, int p) {
map<int, int> hash; hash.clear();
b %= p;
int t = (int)sqrt(p) + 1;
for(int j = 0; j < t; j++) {
int val = (long long) b * power(a, j, p);
hash[val] = j;
}
a = power(a, t, p);
if(a == 0) return b == 0 ? 1 : -1;
for(int i = 0; i <= t; i++) {
int val = power(a, i, p);
int j = hash.find(val) == hash.end() ? -1 : hash[val];
if(j >= 0 && i * t - j >= 0) return i * t - j;
}
return -1;
}
int main() {
int a, b, p;
scanf("%d %d %d", &a, &b, &p);
printf("%d",BGBS(a, b, p));
return 0;
}
```
上述算法的时间复杂度为 $ \sqrt p $。
※章末练习
------------
- $Part1$:**模板题**
1. [P1495 曹冲养猪](https://www.luogu.org/problemnew/show/P1495)(中国剩余定理)
1. [P3811 【模板】乘法逆元](https://www.luogu.org/problemnew/show/P3811)(乘法逆元)
1. [P1082 同余方程](https://www.luogu.org/problemnew/show/P1082)(扩展欧几里得算法)
1. [P3868 [TJOI2009]猜数字](https://www.luogu.org/problemnew/show/P3868)(中国剩余定理)
1. [P5431 【模板】乘法逆元2](https://www.luogu.org/problemnew/show/P5431)(乘法逆元)
1. [P4777 【模板】扩展中国剩余定理(EXCRT)](https://www.luogu.org/problemnew/show/P4777)(扩展中国剩余定理)
- $Part2$:**练习题**(带*号为选做题目)
7. [P2054 [AHOI2005]洗牌](https://www.luogu.org/problemnew/show/P2054)
1. [P1516 青蛙的约会](https://www.luogu.org/problemnew/show/P1516)
1. [P2155 [SDOI2008]沙拉公主的困惑](https://www.luogu.org/problemnew/show/P2155)
1. [P4861 按钮](https://www.luogu.org/problemnew/show/P4861)
1. [P4195 【模板】exBSGS/Spoj3105 Mod](https://www.luogu.org/problemnew/show/P4195)
1. [P2480 [SDOI2010]古代猪文](https://www.luogu.org/problemnew/show/P2480)
1. [P2485 [SDOI2011]计算器](https://www.luogu.org/problemnew/show/P2485)
1. [P3846 [TJOI2007]可爱的质数](https://www.luogu.org/problemnew/show/P3846)
1. **\***[P3301 [SDOI2013]方程](https://www.luogu.org/problemnew/show/P3301)
1. [P4884 多少个1?](https://www.luogu.org/problemnew/show/P4884)
1. [P3306 [SDOI2013]随机数生成器](https://www.luogu.org/problemnew/show/P3306)
1. [P4774 [NOI2018]屠龙勇士](https://www.luogu.org/problemnew/show/P4774)
1. [P1446 [HNOI2008]Cards](https://www.luogu.org/problemnew/show/P1446)
1. [P3726 [AH2017/HNOI2017]抛硬币](https://www.luogu.org/problemnew/show/P3726)
1. [P2020 [NOI2011]兔农](https://www.luogu.org/problemnew/show/P2020)
**注**:以上题目中第13题 **P2485计算器** 为[质数筛法详解](https://www.luogu.org/blog/Ning-H/primes)一章中选做题目
学习完本章后,[质数筛法详解](https://www.luogu.org/blog/Ning-H/primes)中的部分选做题目也可以完成。
$END$
------------
$PS:$
1. **部分材料参考于李煜东《算法竞赛进阶指南》。**
1. **部分材料来源于百度百科。**
1. **中国剩余定理部分资料参考[ 中国剩余定理 && 扩展中国剩余定理](https://blog.csdn.net/niiick/article/details/80229217)**