简单数论杂烩
前言:这是笔者根据 oiwiki,一些大佬的博客和自己的理解写出来的(主要是给自己看的)博客。\(\LaTeX\) 与代码部分均为笔者手打。如有抄袭请联系笔者。
前置算法:欧几里得法求最大公约数,快速幂,欧拉筛(线性筛)。
1. 定理
1.1 费马小定理
结论:设 \(p\) 为质数,则 \(a^{-1} \equiv 1 \pmod p\)(\(a\) 不为 \(p\) 的倍数)。
证明:
显然对于两数 \(a,b\),若 \(\gcd(a,b)=1\) 且 \(ab \equiv 0 \pmod p\),则有 \(a \equiv 0 \pmod p\) 或 \(b \equiv 0 \pmod p\)。
引理:设 \(\gcd(a,p)=1\),对于 \(1\) 到 \(p-1\),每个数乘 \(a\) 在模 \(p\) 的意义下是互不相同的,且对应 \(1\) 到 \(p-1\) 每个数。
为什么?反证法,若存在两个数 \(n,m\) 满足 \(1 \le n,m \le p-1\) 且 \(n \neq m\),使得 \(na \equiv ma \pmod p\),则有 \((n-m)a \equiv 0 \pmod p\),所以需要满足 \(n-m \equiv 0 \pmod p\) 或者 \(a \equiv 0 \pmod p\)。
\(a\) 与 \(p\) 互质,所以 \(n-m \equiv 0 \pmod p\)。那么 \(|n-m| \ge p-1\) 也就不满足条件。
我们将 \(1\) 到 \(p-1\) 的每个数相乘,将 \(a\),\(2a\),……,\((p-1)a\) 相乘,那么它们在模 \(p\) 意义下相等,即 \(\displaystyle \prod_{i=1}^{p-1} i \equiv a^{p-1} \prod_{i=1}^{p-1} i \pmod p\)。
所以 \(\displaystyle (a^{p-1}-1) \prod_{i=1}^{p-1} i \equiv 0 \pmod p\)。
因为 \(\displaystyle \prod_{i=1}^{p-1} i \ge 0\),所以 \(a^{p-1}-1 \equiv 0 \pmod p\),即 \(a^{p-1} \equiv 1 \pmod p\)。
1.2 裴蜀定理
结论:对于不定方程 \(ax+by=c\),当 \(\gcd(a,b) \mid c\) 时方程有整数解。
证明:
设 \(d=\gcd(a,b)\),当 \(d>1\) 时,若 \(d \nmid c\) 则方程无整数解,否则两边同时除以 \(d\),转化为 \(d=1\) 的情况。
\(d=1\) 时,考虑 \(ax \bmod b\) 是否可以凑出 \(0\) 到 \(b-1\) 的任意整数。根据 1.1 中给出的引理,只需要 \(x\) 从 \(0\) 取到 \(b-1\) 即可。
则 \(ax+by=by'+r(0 \le r \le b-1)\),取 \(\displaystyle y'= \lfloor \frac{c}{b} \rfloor,r=c \bmod b\),可得 \(ax+by=c\)。
2. 一些东西
2.1 扩展欧几里得算法
用途:扩展欧几里得算法可以在 \(O(\log_2 \max(a,b))\) 的时间复杂度内求出二元一次不定方程 \(ax+by=\gcd(a,b)\) 的一组可行整数解。
流程:
根据欧几里得算法有 \(\gcd(a,b)=\gcd(b,a \bmod b)\)。
所以方程 \(bx+(a \bmod b)y=\gcd(b,a \bmod b)=\gcd(a,b)\) 有整数解。解这个不定方程得到一组整数解 \((x',y')\)。
于是
令 \(\biggl\{^{\displaystyle x=y'}_{\displaystyle y=x'-\lfloor \frac{a}{b} \rfloor \times y'}\),不断递归缩小问题规模,我们就可以在使用欧几里得算法求解 \(\gcd(a,b)\) 的同时求解 \(ax+by=\gcd(a,b)\) 的一组整数解。边界情况,\(b=0\) 时,有\(\gcd(a,b)x=\gcd(a,b)\),则 \(\biggl\{^{\displaystyle x=1}_{\displaystyle y=0}\) 为一组可行解。
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 t=x;
x=y;
y=t-(a/b)*y;
return d;
}
2.2 逆元
定义:若 \(ax \equiv 1 \pmod m\),则称 \(x\) 为 \(a\) 在 \(\text{mod} \ m\) 意义下的乘法逆元。也可写作 \((a^{-1})_{m}\)。
显然只有 \(\gcd(a,m)=1\) 时 \((a^{-1})_{m}\) 存在。
求法:
费马小定理法:
要求 \(m\) 为质数。
根据费马小定理有 \(a^{p-1} \equiv a^{p-2} \times a \equiv -1 \pmod m\)。
所以 \(a^{p-2} \equiv a^{-1} \pmod m\)。快速幂解决即可。
扩展欧几里得法:
无其他要求。
注意到 \(ax \equiv 1 \pmod m\) 可以转化成一个二元一次不定方程 \(ax-my=1\),而 \(\gcd(a,m)=1\),扩展欧几里得算法解出 \(x\) 即可。
离线 \(O(n)\) 求多个数逆元:
令这些数分别为 \(a_1,a_2,...,a_n\)。算出它们的前缀积 \(\displaystyle b_k=\prod_{i=1}^k a_i\)。令 \(b_0=1\)。
求出 \((b_n^{-1})_m\),则 \(b_k^{-1} \equiv b_{k+1}^{-1} \times a_{k+1} \pmod m\),\(a_k^{-1} \equiv b_k^{-1} \times b_{k-1} \pmod m\)。总时间复杂度 \(O(n+\log_2 n)=O(n)\)。
int m;
int a[N],b[N],inv_a[N],inv_b;
//...
inv_b=qpow(a,m-2,m);//int tmp;exgcd(b[n],m,inv_b,tmp);
inv_a[n]=inv_b*b[n-1];
for(int i=n-1;i>=1;i--){
inv_b=1ll*inv_b*a[i+1]%m;
inv_a[i]=1ll*inv_b*b[i-1]%m;
}
2.3 中国剩余定理(参考 oiwiki)
用途:中国剩余定理(Chinese Remainder Theorem,简称 CRT)可以用于求解同余方程组
的解。其中 \(\forall i,j,1 \le i,j \le n,i \neq j\),有 \(\gcd(m_i,m_j)=1\)。(即模数两两互质)
流程:
- 令 \(\displaystyle M=\prod_{i=1}^{n} m_i\)。
- 对于每个方程,计算 \(\displaystyle \frac{M}{m_i}\) 模 \(m_i\) 下的逆元 \(\displaystyle (\frac{M}{m_i})^{-1}\)。
- 方程在模 \(M\) 意义下的唯一解为 \(\displaystyle x=\sum_{i-1}^{n} a_i \frac{M}{m_i} (\frac{M}{m_i})^{-1}\)。
证明:
显然,当 \(i \neq j\) 时,有 \(\displaystyle \frac{M}{m_i} \equiv 0 \pmod {m_j}\),那么 \(\displaystyle \frac{M}{m_i} (\frac{M}{m_i})^{-1} \equiv \frac{M}{m_i} \equiv 0 \pmod {m_j}\)。
根据逆元定义,\(\displaystyle \frac{M}{m_i} (\frac{M}{m_i})^{-1} \equiv 1 \pmod {m_i}\)。
则对于第 \(i\) 个方程组,有:
这样就证明了 CRT 的正确性。
for(int i=1;i<=n;i++)
M*=m[i];
for(int i=1;i<=n;i++){
exgcd(M/m[i]%m[i],m[i],x,y);
(ans+=(a[i]*M/m[i]*((x%m[i]+m[i])%m[i]))%M)%=M;
}
扩展
用于解决模数不互质的情况。
设 \(x \equiv a_1 \pmod{m_1}\),\(x \equiv a_2 \pmod{m_2}\)。
将其转为不定方程,则有 \(x=m_1 x_1+a_1=m_2 x_2+a_2\)。
那么 \(m_1 x_1-m_2 x_2=a_2-a_1\)。
由裴蜀定理,当 \(\gcd(m_1,m_2) \nmid a_2-a_1\) 时,方程无解。
否则,通过扩欧得到一组可行解。
那么可将两个同余方程合并为一个方程 \(x \equiv m_1 x_1+a_1 \pmod{\text{lcm}(m_1,m_2)}\)。
重复合成 \(n-1\) 次即可将 \(n\) 个同余方程合并成一个同余方程。
#define i128 __int128
for(int i=1;i<=n;i++){
read(m);read(a);
if(i==1){
M=m;
x=a;
continue;
}
i128 inv,tmp;
i128 d=exgcd(M,m,inv,tmp);//m1x1-m2x2=a2-a1
if((a-x)%d!=0){
cout<<-1;
return 0;
}
i128 mod=M*m/d;
x=(inv*(a-x)/d%mod*M%mod+x)%mod;
M=mod;
x=(x%M+M)%M;
}
2.4 欧拉函数(参考 oiwiki)
定义:
欧拉函数 \(\varphi(n)\),表示 \(1\) 到 \(n\) 中与 \(n\) 互质的数的个数。如 \(\varphi(8)=4\),因为在 \(1\) 到 \(8\) 中有 \(1、3、5、7\) 共 \(4\) 个数与 \(8\) 互质。
性质:
-
设 \(p\) 为任意质数,则 \(\varphi(p)=p-1\)。
-
欧拉函数是积性函数,即当 \(\gcd(a,b)=1\),有 \(\varphi(ab)=\varphi(a) \varphi(b)\)。
-
对于任意正整数 \(n\) 有 \(\displaystyle n=\sum_{d \mid n} \varphi(d)\)。
-
设 \(\displaystyle n=\prod_{i=1}^{x} p_i^{k_i}\)(其中 \(p_i\) 为质数),有 \(\displaystyle \varphi(n)=n \times \prod_{i=1}^{x} \frac{p_i-1}{p_i}\)。
欧拉定理等学了之后再写。
求法:
质因数分解:
根据性质:\(\displaystyle \varphi(n)=n \times \prod_{i=1}^{x} \frac{p_i-1}{p_i}\),对 \(n\) 作质因数分解的同时计算 \(\varphi(n)\) 即可。
int phi(int x){
int res=x;
for(int i=2;i*i<=x;i++){
if(x%i)continue;
res=res/i*(i-1);
while(n%i==0)x/=i;
}
if(n>1)res=res/x*(x-1);
return res;
}
线性筛(也叫欧拉筛):
(名字里居然都有欧拉。欧拉好闪,拜谢欧拉。/bx)
以下是一个线性筛模板:
vector<int> pri;
bool flag[N];
void init(int n){
for(int i=2;i<=n;i++){
if(!flag[i])
pri.push_back(i);
for(int p:pri){
if(i*p>n)break;
flag[i*p]=flag;
if(i%p==0)break;
}
}
}
注意到:对于一个合数 \(n\),由于线性筛确保每个合数只会被筛一次,所以 \(n\) 会被它的最小质因子筛掉。
设这个最小质因子为 \(p\),令 \(\displaystyle n'=\frac np\),我们分两种情况进行讨论:
- 当 \(p \mid n'\),则 \(n'\) 包含 \(n\) 的所有质因子,则:
- 当 \(p \nmid n'\),则根据欧拉函数的积性,有
分情况计算即可。
vector<int> pri;
int phi[N];
bool flag[N];
void init(int n){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!flag[i]){
pri.push_back(i);
phi[i]=i-1;
}
for(int p:pri){
if(i*p>n)break;
flag[i*p]=flag;
if(i%p==0){
phi[i*p]=p*phi[i];
break;
}
phi[i*p]=(p-1)*phi[i];
}
}
}
2.5 数论分块
用于在 \(O(\sqrt{n})\) 复杂度内求出 \(\displaystyle \sum_{i=1}^{n} f(i) \lfloor \frac{n}{i} \rfloor\)。
结论:
使得 \(\displaystyle \lfloor \frac{n}{i} \rfloor = \lfloor \frac{n}{j} \rfloor\) 成立且 \(i \le j \le n\) 的最大的 \(j=\displaystyle \lfloor \frac{n}{\lfloor \frac{n}{i} \rfloor} \rfloor\)。
计算过程:
持续更新中。。。

浙公网安备 33010602011771号