初等数论及组合数学入门复习概览
同步于 博客园 和 洛谷博客。
由于各网站之间
质数
定义:无法被任何除了
性质:
判断质数
- 试除法:
时间复杂度
bool isPrime(int n){
if (n<2) return 0;
int k=sqrt(n);
F(i,2,k)
if (!(n%i)) return 0;
return 1;
}
质数筛
- 埃氏筛:
对于每个整数,显然其倍数都不是质数。
扫描所有数,每扫到一个没被标记的数,该数即为质数,随后标记该数的倍数为约数。
同时,对于当前的质数
时间复杂度
bool vis[N];
void EratosthenesSeive(int n){
F(i,2,n){
if (vis[i]) continue;
F(j,i,n/i) vis[i*j]=1;
}
return ;
}
- 线性筛(欧拉筛):
埃氏筛依旧会重复标记某些合数,考虑使合数被唯一标记。
设
对于每个数,扫描质数集的所有数
时间复杂度
vector<int> prime;
int v[N];
void EulerSeive(int n){
F(i,2,n){
if (!v[i]) v[i]=i,prime.push_back(i);
V(x,prime){
if (x>v[i]||i*x>n) break;
v[i*x]=x;
}
}
return ;
}
质因数分解
前置知识:
- 唯一分解定理:任意一个大于
1 的正整数n 都可被唯一分解为若干个质数的乘积,即n=p_1^{c_1}p_2^{c_2}\dots p_k^{c_k} ,其中c_i 为正整数,p_i 为质数且p_1 < p_2 < \dots < p_k 。
int p[N],c[N],tot;
void Divide(int n){
int k=sqrt(n);
F(i,2,k){
if(!(n%i)){
p[++tot]=i,c[tot]=0;
while(!(n%i)) ++c[tot],n/=i;
}
}
if (n>1) p[++tot]=n,c[tot]=1;
return ;
}
约数
定义:若
求单个值的正约数集合
- 试除法:
因为若
故从
推论:一个整数
时间复杂度
vector<int> fac;
void FactorDivision(int n){
int k=sqrt(n);
F(i,1,k){
if (!(n%i)){
fac.push_back(i);
if (i!=n/i) fac.push_back(n/i);
}
}
return ;
}
求区间内的正约数集合
- 暴力+试除法:
时间复杂度
- 倍数法:
反过来考虑,运用埃氏筛的倍数标记思想,对于每个数
时间复杂度
vector<int> fac[N];
void FactorDivision(int n){
F(i,1,n)
F(j,1,n/i)
fac[i*j].push_back(i);
return ;
}
数论分块
例题:给定正整数
显然
对于每个块,设
时间复杂度
int mathBlock(int n){
int l=1,r,ans=0;
while(l<=n){
r=n/(n/l);
ans+=(n/l)*(r-l+1);
l=r+1;
}
return ans;
}
题目:
- [AHOI2005]约数研究
- 约数和
最大公约数 最小公倍数
前置知识:
-
公约数:若
x\mid a 且x\mid b ,则称x 为a 和b 的公约数。 -
公倍数:若
a\mid x 且b\mid x ,则称x 为a 和b 的公倍数。
显然最大公约数就是公约数中最大的数字,最小公倍数就是公倍数中最小的数字。
求最大公约数
- 欧几里得算法:
设
a > b 且a=bk+c ,则有c=a\bmod b 。 设d\mid a,d\mid b ,则有:\begin{aligned} c=a-bk\\ \frac{c}{d}=\frac{a}{d}-\frac{b}{d}k \end{aligned} 由对
d 的定义可知d\mid c ,故\gcd(a,b)=\gcd(b,a\bmod b) ,得证。
时间复杂度
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
- 更相减损术:
当
a=b 时,显然\gcd(a,b)=a=b 。 设a\geq b ,那么\forall d\mid a,d\mid b 有d\mid a-b 。 故a 和b 的所有公约数都为a-b 和b 的公约数,\gcd(a,b)=\gcd(a-b,b) ,得证。
时间复杂度
int gcd(int a,int b){
while(a!=b){
if (a>b) a-=b;
else b-=a;
}
return a;
}
- 更相减损术优化:
若
反之,则若
当
时间复杂度
int gcd(int a,int b){
int aa=0,bb=0;
while(!(a&1)) a>>=1,++aa;
while(!(b&1)) b>>=1,++bb;
while(1){
while(!(a&1)) a>>=1;
while(!(b&1)) b>>=1;
if (a==b) break;
if (a<b) swap(a,b);
a-=b;
}
return a<<min(aa,bb);
}
求最小公倍数
由唯一分解定理,可使
a=p_1^{c_{a_1}}p_2^{c_{a_2}}\dots p_k^{c_{a_k}},b=p_1^{c_{b_1}}p_2^{c_{b_2}}\dots p_k^{c_{b_k}} 。 则最大公约数为p_1^{\min(c_{a_1},c_{b_1})}p_2^{\min(c_{a_2},c_{b_2})}\dots p_k^{\min(c_{a_k},c_{b_k})} ,最小公倍数为p_1^{\max(c_{a_1},c_{b_1})}p_2^{\max(c_{a_2},c_{b_2})}\dots p_k^{\max(c_{a_k},c_{b_k})} 。 由于\min(c_a,c_b)+\max(c_a,c_b)=c_a+c_b ,所以\gcd(a,b)\times \operatorname{lcm}(a,b)=a\times b ,得证。
时间复杂度为求最大公约数的时间复杂度。
int lcm(int a,int b){
// 先除后乘可防止爆 int。
return a/gcd(a,b)*b;
}
欧拉函数
前置知识:
-
互质:
\forall x,y\in \mathbb{N} ,若\gcd(x,y)=1 ,则称x 和y 互质,记作x\perp y 。 -
积性函数:若
x,y 互质且f(x)\times f(y)=f(xy) ,则称函数f 为积性函数。 -
完全积性函数:若
\forall x,y\in \mathbb{R} ,f(x)\times f(y)=f(xy) ,则称f 为完全积性函数。
定义:
性质:
-
若
n 为质数,则\varphi(n)=n-1 。 -
\because \gcd(n,x)=\gcd(n,n-x) $\therefore$ 与 $n$ 互质的数的平均值为 $\frac{n}{2}$,而与 $n$ 互质的数有 $\varphi(n)$ 个,得证。
-
-
若
n=p^k ,且p 为质数,则\varphi(n)=(p-1)\times p^{k-1} 。
根据唯一分解定理,可知
n 与p 的倍数都不互质,与其它数均互质。
- 若
p 为质数,且p 为n 的约数,则\varphi(np)=\varphi(n)\times p 。
因为
p 为质数,所以np 和n 的质因子相同,仅p 的指数不同,故(计算公式见求单个值的欧拉函数):\frac{\varphi(np)}{\varphi{(n)}}=\frac{np\times\prod_{i=1}^{k}(1-\frac{1}{p_i})}{n\times \prod_{i=1}^{k}(1-\frac{1}{p_i})}=\frac{np}{n}=p 所以
\varphi(np)=\varphi(n)\times p ,得证。
- 若
p 为质数且p 不为n 的约数,则\varphi(np)=\varphi(n)\times (p-1) 。
因为
p 不为n 的约数,所以p\perp n 。 故\varphi(np)=\varphi(n)\times \varphi(p)=\varphi(n)\times (p-1) ,得证。
-
\sum_{d\mid n}\varphi(d)=n
设
f(x)=\sum_{d\mid n}\varphi(d) ,因为\varphi 为积性函数,所以若a,b 互质,则f(ab)=\sum_{d\mid ab}\varphi(d)=(\sum_{d\mid a}\varphi(d))\times (\sum_{d\mid b}\varphi(d)) ,所以f 为积性函数。 对于一个质因子p^k ,f(p^k)=\sum_{d\mid p^k}\varphi(d)=\varphi(1)+\varphi(p)+\dots+\varphi(p^k) ,结果为等比数列求和加1 ,结果为p^k 。 故f(n)=\prod_{i=1}^{k}f(p_i^{c_i})=\prod_{i=1}^{k}p_i^{c_i}=n ,得证。
求单个值的欧拉函数
通过唯一分解定理,使
对于
n 的所有质因子p_i ,在1\sim n 范围内p_i 的倍数有\frac{n}{p_i} 个。 那么对于n 的两个质因子p,q ,根据容斥,1\sim n 范围内含质因子p 或q 的数的个数为\frac{n}{p}+\frac{n}{q}-\frac{n}{pq} 。 不含质因子p 或q 的数的个数为n-\frac{n}{p}-\frac{n}{q}+\frac{n}{pq}=n\times (1-\frac{1}{p}-\frac{1}{q}+\frac{1}{pq})=n(1-\frac{1}{p})(1-\frac{1}{q}) ,将公式扩展到所有质因子p_i 即可得证。
故在分解质因数时即可求出
int Phi(int n){
int ans=n,k=sqrt(n);
F(i,2,k){
if (!(n%i)){
ans=ans/i*(i-1);
while (!(n%i)) n/=i;
}
}
if (n>1) ans=ans/n*(n-1);
return ans;
}
求区间内的欧拉函数
- 暴力:
代码见求单个数的欧拉函数,时间复杂度
- 埃氏筛:
时间复杂度
int phi[N];
void CalculatePhi(int n){
F(i,1,n) phi[i]=i;
F(i,2,n){
if (phi[i]==i)
for (int j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i+1);
}
return ;
}
- 线性筛:
时间复杂度
int phi[N],v[N];
vector<int> prime;
void CalculatePhi(int n){
phi[1]=1;
F(i,2,n){
if (!v[i])
v[i]=i,phi[i]=i-1,prime.push_back(i);
V(x,prime){
if (x>v[i]||i*x>n) break;
v[i*x]=x;
phi[i*x]=phi[i]*(i%x?x-1:x);
}
}
return ;
}
题目:
- GCD SUM
- [SDOI2008] 仪仗队
莫比乌斯函数
定义:若根据唯一分解定理使正整数
特别地,
求单个值的莫比乌斯函数
- 质因数分解:
时间复杂度
int Mobius(int n){
if (n==1) return 1;
int k=sqrt(n),cnt=0;
F(i,2,k){
if (!(n%i)){
int ci=0;
while(!(n/i)) n/=i,++ci;
if (ci>1) return 0;
++cnt;
}
}
if (n>1) ++cnt;
return cnt&1?-1:1;
}
求区间内的莫比乌斯函数
- 埃氏筛:
先初始化
时间复杂度
int mu[N];
bool vis[N];
void Mobius(int n){
fill(mu+1,mu+1+n,1);
F(i,2,n){
if (vis[i]) continue;
mu[i]=-1;
for (int j=(i<<1);j<=n;j+=i){
v[j]=1;
if (!((j/i)%i)) mu[i]=0;
else mu[i]*=-1;
}
}
return ;
}
- 线性筛:
对于质数
时间复杂度
vector<int> prime;
int mu[N];
bool vis[N];
void Mobius(int n){
mu[1]=1;
F(i,2,n){
if (!vis[i]) vis[i]=1,mu[i]=-1,prime.push_back(i);
V(x,prime){
if (i*x>n) break;
vis[i*x]=1;
if (!(i%x)) break;
mu[i*x]=-mu[i];
}
}
return ;
}
同余
前置知识:
- 取模的定义式:
定义:若
性质:
-
自反性:
x\equiv x\pmod p 。 -
对称性:若
x\equiv y\pmod p ,则y\equiv x\pmod p 。 -
传递性:若
x\equiv y\pmod p 且y\equiv z\pmod p ,则x\equiv z\pmod p 。 -
同余式相加性:若
x\equiv y\pmod p 且a\equiv b\pmod p ,则(x\pm a)\equiv (y\pm b)\pmod p 。 -
同余式相乘性:若
x\equiv y\pmod p 且a\equiv b\pmod p ,则ax\equiv by\pmod p 。
乘法逆元
前置知识:
- 费马小定理:若
p 为质数且a\perp p ,则a^p\equiv a\pmod p 。
定义:若
求单个值的乘法逆元
若
- 快速幂:若
p 为质数,且a\perp p ,根据费马小定理,可知a 模p 的乘法逆元为a^{p-2}\bmod p 。
由费马小定理可知
a^{p-1}\equiv 1\pmod p 。 而我们要求ax\equiv 1\pmod p 的解,由传递性可得:\begin{aligned} ax\equiv a^{p-1}\pmod p\\ x\equiv a^{p-2}\pmod p \end{aligned} 得证。
- 扩展欧几里得算法:将方程改写为
ax+py=1 ,使用扩展欧几里得算法求出x 即可。
题目:
- [NOIP2012 提高组] 同余方程
求区间内的乘法逆元
- 暴力+快速幂:
仅适用于
- 暴力+扩展欧几里得算法:
代码见扩展欧几里得算法,时间复杂度
- 线性递推:
\therefore facinv_{i+1}\times (i+1)=\frac{1}{i!}=facinv_i 得证。
时间复杂度
欧拉定理
前置知识:
-
同余类:
\forall a\in[0,m-1] ,集合\{a+km\}(k\in \mathbb{Z}) 的所有数模m 同余,余数均为a ,则称该集合为一个模m 的同余类,记为\overline{a} 。 -
完全剩余系:
m 个模m 的同余类\overline{i} (i\in[0,m-1]) 所构成的集合称为完全剩余系。 -
简化剩余系:
\varphi(m) 个与m 互质的数的同余类所构成的集合称为简化剩余系。 -
费马小定理:见乘法逆元。
定义:若
扩展欧拉定理
题目:
-
【模板】扩展欧拉定理
-
[六省联考 2017] 相逢是问候
扩展欧几里得算法
前置知识:
-
欧几里得算法:见求最大公约数。
-
裴蜀定理(Bézout 定理):
\forall a,b\in \mathbb{Z},\exists x,y\in \mathbb{Z},ax+by=\gcd(a,b) 。
在欧几里得算法的最后一步,即
b=0 时,显然存在x=1,y=0 使a\times 1+0\times 0=\gcd(a,0) 。 考虑当b>0 时,\gcd(a,b)=\gcd(b,a\bmod b) ,设存在一对整数x,y 使得\gcd(b,a\bmod b)=bx+(a\bmod b)y 。 由取模的定义式,可转化bx+(a\bmod b)y=bx+(a-b\lfloor \frac{a}{b} \rfloor)y=ay+b(x-\lfloor \frac{a}{b} \rfloor y) 。 故当x^{\prime}=y,y^{\prime}=x-\lfloor \frac{a}{b} \rfloor y 时,有ax^{\prime}+by^{\prime}=\gcd(a,b) ,对递归过程使用数学归纳法即可得证。
对于求
int exgcd(int a,int b,int &x,int &y){
if (!b){
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;
}
题目:
- 【模板】二元一次不定方程 (exgcd)
中国剩余定理
前置知识:
- 乘法逆元:见乘法逆元。
若
设
$\therefore \forall k\neq i,a_kM_kt_k\equiv 0\pmod {p_k} \because t_i\equiv(M_i)^{-1}\pmod {p_i} \therefore a_iM_it_i\equiv a_i\pmod {p_i} 由同余式相加性且
m=\prod_{i=1}^{n}{p_i} 可知x 在展开之后即为\sum_{i=1}^{n}{a_iM_it_i}\bmod m ,得证。
时间复杂度
int CRT(int n){
F(i,1,n){
exgcd(M/p[i],p[i],x,y);
x=(x%p[i]+p[i])%p[i];
ans+=x*a[i]*(M/p[i]),ans%=M;
}
return ans;
}
题目:
- 【模板】中国剩余定理(CRT)/ 曹冲养猪
扩展中国剩余定理
前置知识:
- 扩展欧几里得算法:见扩展欧几里得算法。
若
考虑
若
则
扩展到
时间复杂度
int exCRT(int n){
int ret=a[1],cur=p[1],x,y;
F(i,2,n){
int gcd=exgcd(cur,p[i],x,y),c=((a[i]-ret)%p[i]+p[i])%p[i];
if (c%gcd) return -1;
x=quick_mul(x,c/gcd,p[i]/gcd);
ret+=x*cur;
cur=cur/gcd*p[i];
ret=(ret%cur+cur)%cur;
}
return (ret%cur+cur)%cur;
}
题目:
- 【模板】扩展中国剩余定理(EXCRT)
组合
加法原理 乘法原理
加法原理(分类):一个问题有
乘法原理(分布):一个问题有
容斥原理
当
当
通项式:
德摩根定律
简记:交之补等于补之并,并之补等于补之交。
推论:
\begin{aligned} |\bigcup_{i=1}^{n}A_i|=\sum_{\varnothing \neq J=\subseteq\{1,2,\dots,n\}}(-1)^{|J|-1}|\bigcap_{j\in J}A_j|\\ |\bigcap_{i=1}^{n}\overline{A_i}|=\sum_{\varnothing \neq J\subseteq \{1,2,\dots,n\}}(-1)^{|J|}|\bigcap_{j\in J} A_j|\\ |\bigcap_{i=1}^{n}{A_i}|=\sum_{\varnothing \neq J\subseteq \{1,2,\dots,n\}}(-1)^{|J|}|\bigcap_{j\in J} \overline{A_j}| \end{aligned}
排列数 组合数
排列数:
组合数:
特别地,若
性质:
-
C_{n}^{0}=1$,$C_{n}^{1}=n$,$C_{n}^{2}=\frac{n(n-1)}{2} -
C_{n}^{k}=C_{n}^{n-k} -
C_{n}^{k}=C_{n-1}^{k}+C_{n-1}^{k-1} -
\sum_{i=0}^{n}C_{n}^{i}=2^n
求组合数
- 暴力:
int C(int n,int k,int p){
int a=1,b=1;
F(i,0,k-1) a*=(n-i);
F(i,1,k) b*=i;
return (a/b)%p;
}
时间复杂度 long long)。
- 递推预处理:
由性质
3 得证。
void InitC(int n,int p){
F(i,0,n){
C[i][0]=1;
F(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
}
return ;
}
时间复杂度
- 预处理阶乘+逆元:
这里使用了快速幂求逆元。
int C(int n,int k,int p){
if (!k) return 1;
return (fac[n]*ksm(fac[n-k],p-2,p)%p*ksm(fac[k],p-2,p)%p)%p;
}
时间复杂度
- 卢卡斯定理:
见卢卡斯定理,仅限
- 扩展卢卡斯定理:
当
二项式定理
对于每一个
(x+y) ,显然要么选x ,要么选y 。 若有k 个(x+y) 选择y ,则有n-k 个选择x ,由于要选取k 个(x+y) ,故系数为C_{n}^{k} 。 因为k 为分类,所以利用加法原理,得证。
计数技巧
等价替代
对于某些计数题,正面解决可能会很困难,这时可以用一些方法将问题转化为另一种更为容易计算的问题。
捆绑法
若要求某些物品相邻,则可将所需相邻的物品看做一个整体,然后计算排列,再分别计算每个整体内的排列相乘。
例题:有
可先将
\text{AB} 和\text{CD} 看作一个整体,然后对剩下的3 个物品进行排列,有A_{3}^{3}=6 种排列方案。 然后再计算各个整体内的排列,A_{2}^{2}=2 种。 故共有2\times A_{2}^{2}\times A_{3}^{3}=24 种排列方案。
插空法
若要求某些物品两两不相邻,则可先将其它的物品排好,然后再从空当中插入,分别计算排列后相乘。
例题:有
先对其它
4 种物品进行排列,有A_{4}^{4}=24 种方案。 然后将剩下3 种物品插入到其中的5 个空当中,有A_{5}^{3}=60 种方案,故共有A_{4}^{4}\times A_{5}^{3}=1440 种排列方案。
隔板法
至少分配问题和不定方程整数解问题可转化为关于插板的组合问题。
例题
将
n 件物品排成一行,中间有k-1 个隔板,表示每个人分到的部分,而k-1 个隔板只能插入到n-1 个空当中,故方案数为C_{n-1}^{k-1} 。
例题
可将题意抽象为数学模型,求方程
\sum_{i=1}^{k}x_i=n 的解,其中x_i\geq 1 。 若改限制为x\geq 0 ,则设y_i=x_i+1 ,转化为\sum_{i=1}^{k}=n+k 。 再结合上题的解,即可求出方案数为C_{n+k-1}^{k-1} 。
改变计数目标
对于某些计数题,直接解决可能会很困难,可以用减法原理或容斥原理等内容转化为容易求的问题。
改变枚举顺序
对于某些计数题,直接枚举只能拿到暴力分,可以改变枚举顺序使其更容易计算。
例题:求
\begin{aligned} \sum_{i=1}^{n}\sum_{j=1}^{n}\max(i,j)\\ =\sum_{k=1}^{n}k\sum_{i=1}^{n}\sum_{j=1}^{n}[\max(i,j)=k]\\ =\sum_{k=1}^{n}k(2k-1)\\ =2\sum_{k=1}^{n} k^2 -\frac{(n+1)n}{2}\\ =\frac{4n^3+3n^2-n}{6} \end{aligned}
多重集的排列组合数
多重集:指包含重复元素的广义集合。
多重集的排列数
设
多重集的组合数
设
设对于每一个
a_i 选取x_i 个,则问题可转化为\sum_{i=1}^{k}x_i=r(x_i\geq 0) 的不定方程。 用隔板法求解即可。
卢卡斯定理
模数
其中对于左半部分进行递归,右半部分直接进行计算,因为
时间复杂度
int fac[N],facinv[N];
void Init(int n,int p){
fac[0]=1;
F(i,1,n) fac[i]=fac[i-1]*i,fac[i]%=p;
facinv[n]=ksm(fac[n],p-2,p);
FJ(i,n-1,0) facinv[i]=facinv[i+1]*(i+1),facinv[i]%=p;
return ;
}
int C(int n,int m,int p){
if (m>n) return 0;
return ((fac[n]*facinv[m])%p*facinv[n-m])%p;
}
int Lucas(int n,int m,int p){
if (!m||n==m) return 1;
return (Lucas(n/p,m/p,p)*C(n%p,m%p,p))%p;
}
int Solve(int n,int m,int p){
Init(p-1,p);
return Lucas(n,m,p);
}
卡特兰数
定义:一种常出现于各种计数问题的数列,记作
卡特兰数列:
常见题型
-
- 入栈序列为
1,2,\dots,n 的合法出栈序列数量?H_n 。 -
- 只能向上或向右走,能从
(0,0) 走到(n,n) 且不接触直线y=x 的路线的数量?2H_{n-1} 。 - 只能向上或向右走,能从
(0,0) 走到(n,n) 且不穿过直线y=x 的路线的数量?H_{n+1} 。
求卡特兰数
以下所有公式均有
- 递推:
- 组合通式: