同步于 博客园 和 洛谷博客。

由于各网站之间 LaTeX\LaTeX 及 Markdown 渲染方式的差异,故不保证除博客园外的排版完好,对于排版有明显不正确的地方请以博客园为主。

质数

定义:无法被任何除了 11 及其本身的自然数整除的数。

性质:

  1. [1,n][1,n] 内大约有 nln⁡n\frac{n}{\ln n} 个质数,即每 ln⁡n\ln n 个数就大约有一个质数。

判断质数

  1. 试除法:

时间复杂度 O(n)\mathcal{O}(\sqrt{n})。

1
2
3
4
5
6
7
bool isPrime(int n){
if (n<2) return 0;
int k=sqrt(n);
F(i,2,k)
if (!(n%i)) return 0;
return 1;
}

质数筛

  1. 埃氏筛:

对于每个整数,显然其倍数都不是质数。

扫描所有数,每扫到一个没被标记的数,该数即为质数,随后标记该数的倍数为约数。

同时,对于当前的质数 xx,因为小于 x2x^2 的 xx 的倍数已经被小于 xx 的质数扫描过了,因此只需要从 x2x^2 开始扫描倍数即可。

时间复杂度 O(nlog⁡log⁡n)\mathcal{O}(n\log \log n)。

1
2
3
4
5
6
7
8
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 ;
}
  1. 线性筛(欧拉筛):

埃氏筛依旧会重复标记某些合数,考虑使合数被唯一标记。

设 viv_i 为 ii 的最小质因子,从前到后扫描所有数,若 vi=0v_i=0 则 ii 为质数,使 vi=iv_i=i 并将 ii 加入到质数集 Prime\text{Prime}。

对于每个数,扫描质数集的所有数 xx,若 xx 相比 viv_i 不是最小的质因子或 i×xi\times x 超出筛的范围则终止扫描,反之则 vi×x=xv_{i\times x}=x。

时间复杂度 O(n)\mathcal{O}(n)。

1
2
3
4
5
6
7
8
9
10
11
12
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. 唯一分解定理:任意一个大于 11 的正整数 nn 都可被唯一分解为若干个质数的乘积,即 n=p1c1p2c2…pkckn=p_1^{c_1}p_2^{c_2}\dots p_k^{c_k},其中 cic_i 为正整数,pip_i 为质数且 p1<p2<⋯<pkp_1 < p_2 < \dots < p_k。
1
2
3
4
5
6
7
8
9
10
11
12
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 ;
}

约数

定义:若 n mod d=0n\bmod d=0,则称 dd 为 nn 的约数,记作 d∣nd\mid n,读作 dd 整除 nn。

求单个值的正约数集合

  1. 试除法:

因为若 dd 为 nn 的约数,则 nd\frac{n}{d} 也为 nn 的约数,所以除完全平方数的 n\sqrt n 之外,约数总是成对出现的。

故从 1∼n1\sim \sqrt n 判断 ii 是否整除 nn 即可,若整除且 i≠nii\neq \frac{n}{i} 则 ni\frac{n}{i} 也为约数。

推论:一个整数 nn 至多有 2n2\sqrt n 个约数。

时间复杂度 O(n)\mathcal{O}(\sqrt n)。

1
2
3
4
5
6
7
8
9
10
11
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 ;
}

求区间内的正约数集合

  1. 暴力+试除法:

时间复杂度 O(nn)\mathcal{O}(n\sqrt n),代码见求单个值的正约数集合。

  1. 倍数法:

反过来考虑,运用埃氏筛的倍数标记思想,对于每个数 dd,dd 肯定为其的倍数的约数,故对于每个数,将这个数加入到这个数的倍数的正约数集合里。

时间复杂度 O(nlog⁡n)\mathcal{O}(n\log n)。

1
2
3
4
5
6
7
vector<int> fac[N];
void FactorDivision(int n){
F(i,1,n)
F(j,1,n/i)
fac[i*j].push_back(i);
return ;
}

数论分块

例题:给定正整数 nn,求 ∑i=1n⌊ni⌋\sum_{i=1}^{n}\lfloor \frac{n}{i} \rfloor,其中 1≤n≤1091\leq n\leq 10^9。

显然 ni\frac{n}{i} 在连续的区间内值相等,故可以分成若干块再进行计算。

对于每个块,设 ll 为该块的左边界,那么这个块的值为 k=⌊nl⌋k=\lfloor \frac{n}{l} \rfloor,那么右边界 rr 即为最大的 ii,且满足 i≤nki\leq \frac{n}{k},故 r=⌊nk⌋r=\lfloor \frac{n}{k} \rfloor,代入 kk 得 r=⌊n⌊nl⌋⌋r=\lfloor \frac{n}{\lfloor \frac{n}{l} \rfloor} \rfloor。

时间复杂度 O(n)\mathcal{O}(\sqrt n)。

1
2
3
4
5
6
7
8
9
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;
}

题目:

最大公约数 最小公倍数

前置知识:

  1. 公约数:若 x∣ax\mid a 且 x∣bx\mid b,则称 xx 为 aa 和 bb 的公约数。

  2. 公倍数:若 a∣xa\mid x 且 b∣xb\mid x,则称 xx 为 aa 和 bb 的公倍数。

显然最大公约数就是公约数中最大的数字,最小公倍数就是公倍数中最小的数字。

求最大公约数

  1. 欧几里得算法:

gcd⁡(a,b)=gcd⁡(b,a mod b)\gcd(a,b)=\gcd(b,a\bmod b)

设 a>ba > b 且 a=bk+ca=bk+c,则有 c=a mod bc=a\bmod b。
设 d∣a,d∣bd\mid a,d\mid b,则有:

c=a−bkcd=ad−bdk\begin{aligned} c=a-bk\\ \frac{c}{d}=\frac{a}{d}-\frac{b}{d}k \end{aligned}

由对 dd 的定义可知 d∣cd\mid c,故 gcd⁡(a,b)=gcd⁡(b,a mod b)\gcd(a,b)=\gcd(b,a\bmod b),得证。

时间复杂度 O(log⁡n)\mathcal{O}(\log n)。

1
2
3
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
  1. 更相减损术:

gcd⁡(a,b)=gcd⁡(a−b,b)\gcd(a,b)=\gcd(a-b,b)

当 a=ba=b 时,显然 gcd⁡(a,b)=a=b\gcd(a,b)=a=b。
设 a≥ba\geq b,那么 ∀d∣a,d∣b\forall d\mid a,d\mid b 有 d∣a−bd\mid a-b。
故 aa 和 bb 的所有公约数都为 a−ba-b 和 bb 的公约数,gcd⁡(a,b)=gcd⁡(a−b,b)\gcd(a,b)=\gcd(a-b,b),得证。

时间复杂度 O(max⁡(a,b))\mathcal{O}(\max(a,b))。

1
2
3
4
5
6
7
int gcd(int a,int b){
while(a!=b){
if (a>b) a-=b;
else b-=a;
}
return a;
}
  1. 更相减损术优化:

若 2∣a2\mid a 且 2∣b2\mid b,则 gcd⁡(a,b)=2gcd⁡(a2,b2)\gcd(a,b)=2\gcd(\frac{a}{2},\frac{b}{2})。

反之,则若 2∣a2\mid a 且 2∤b2\nmid b,则 gcd⁡(a,b)=gcd⁡(a2,b)\gcd(a,b)=\gcd(\frac{a}{2},b)。

当 2∤a,2∣b2\nmid a,2\mid b 时同理。

时间复杂度 O(log⁡n)\mathcal{O}(\log n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}

求最小公倍数

gcd⁡(a,b)×lcm⁡(a,b)=a×b\gcd(a,b)\times \operatorname{lcm}(a,b)=a\times b

由唯一分解定理,可使 a=p1ca1p2ca2…pkcak,b=p1cb1p2cb2…pkcbka=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}}。
则最大公约数为 p1min⁡(ca1,cb1)p2min⁡(ca2,cb2)…pkmin⁡(cak,cbk)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})},最小公倍数为 p1max⁡(ca1,cb1)p2max⁡(ca2,cb2)…pkmax⁡(cak,cbk)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⁡(ca,cb)+max⁡(ca,cb)=ca+cb\min(c_a,c_b)+\max(c_a,c_b)=c_a+c_b,所以 gcd⁡(a,b)×lcm⁡(a,b)=a×b\gcd(a,b)\times \operatorname{lcm}(a,b)=a\times b,得证。

时间复杂度为求最大公约数的时间复杂度。

1
2
3
4
int lcm(int a,int b){
// 先除后乘可防止爆 int。
return a/gcd(a,b)*b;
}

欧拉函数

前置知识:

  1. 互质:∀x,y∈N\forall x,y\in \mathbb{N},若 gcd⁡(x,y)=1\gcd(x,y)=1,则称 xx 和 yy 互质,记作 x⊥yx\perp y。

  2. 积性函数:若 x,yx,y 互质且 f(x)×f(y)=f(xy)f(x)\times f(y)=f(xy),则称函数 ff 为积性函数。

  3. 完全积性函数:若 ∀x,y∈R\forall x,y\in \mathbb{R},f(x)×f(y)=f(xy)f(x)\times f(y)=f(xy),则称 ff 为完全积性函数。

定义:∀n>1\forall n>1,∑i=1n[i⊥n]\sum_{i=1}^{n}[i\perp n],记作 φ(n)\varphi(n),特别地,φ(1)=1\varphi(1)=1。

性质:

  1. 若 nn 为质数,则 φ(n)=n−1\varphi(n)=n-1。

  2. ∀n>1\forall n>1,∑i=1n[i⊥n]×i=n2×φ(n)\sum_{i=1}^{n}[i\perp n]\times i=\frac{n}{2}\times \varphi(n)。

∵gcd⁡(n,x)=gcd⁡(n,n−x)\because \gcd(n,x)=\gcd(n,n-x)

∴\therefore 若 xx 不与 nn 互质,则 n−xn-x 也不与 nn 互质,且 xx 和 n−xn-x 总成对出现,其平均值为 n2\frac{n}{2}。

∴\therefore 与 nn 互质的数的平均值为 n2\frac{n}{2},而与 nn 互质的数有 φ(n)\varphi(n) 个,得证。

  1. φ\varphi 为积性函数,即若 x,yx,y 互质,则 φ(xy)=φ(x)×φ(y)\varphi(xy)=\varphi(x)\times \varphi(y)。

  2. 若 n=pkn=p^k,且 pp 为质数,则 φ(n)=(p−1)×pk−1\varphi(n)=(p-1)\times p^{k-1}。

根据唯一分解定理,可知 nn 与 pp 的倍数都不互质,与其它数均互质。

pp 的倍数有 pk−1p^{k-1} 个(含 nn 本身),故 φ(n)=pk−pk−1=(p−1)×pk−1\varphi(n)=p^k-p^{k-1}=(p-1)\times p^{k-1},得证。

  1. 若 pp 为质数,且 pp 为 nn 的约数,则 φ(np)=φ(n)×p\varphi(np)=\varphi(n)\times p。

因为 pp 为质数,所以 npnp 和 nn 的质因子相同,仅 pp 的指数不同,故(计算公式见求单个值的欧拉函数):

φ(np)φ(n)=np×∏i=1k(1−1pi)n×∏i=1k(1−1pi)=npn=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

所以 φ(np)=φ(n)×p\varphi(np)=\varphi(n)\times p,得证。

  1. 若 pp 为质数且 pp 不为 nn 的约数,则 φ(np)=φ(n)×(p−1)\varphi(np)=\varphi(n)\times (p-1)。

因为 pp 不为 nn 的约数,所以 p⊥np\perp n。
故 φ(np)=φ(n)×φ(p)=φ(n)×(p−1)\varphi(np)=\varphi(n)\times \varphi(p)=\varphi(n)\times (p-1),得证。

  1. ∑d∣nφ(d)=n\sum_{d\mid n}\varphi(d)=n

设 f(x)=∑d∣nφ(d)f(x)=\sum_{d\mid n}\varphi(d),因为 φ\varphi 为积性函数,所以若 a,ba,b 互质,则 f(ab)=∑d∣abφ(d)=(∑d∣aφ(d))×(∑d∣bφ(d))f(ab)=\sum_{d\mid ab}\varphi(d)=(\sum_{d\mid a}\varphi(d))\times (\sum_{d\mid b}\varphi(d)),所以 ff 为积性函数。
对于一个质因子 pkp^k,f(pk)=∑d∣pkφ(d)=φ(1)+φ(p)+⋯+φ(pk)f(p^k)=\sum_{d\mid p^k}\varphi(d)=\varphi(1)+\varphi(p)+\dots+\varphi(p^k),结果为等比数列求和加 11,结果为 pkp^k。
故 f(n)=∏i=1kf(pici)=∏i=1kpici=nf(n)=\prod_{i=1}^{k}f(p_i^{c_i})=\prod_{i=1}^{k}p_i^{c_i}=n,得证。

求单个值的欧拉函数

通过唯一分解定理,使 n=p1c1×p2c2×⋯×pkckn=p_1^{c_1}\times p_2^{c_2}\times \dots \times p_k^{c_k},则:

φ(n)=n×p1−1p1×p2−1p2×…pk−1pk=n×∏i=1k(1−1pi)\varphi(n)=n\times \frac{p_1-1}{p_1}\times \frac{p_2-1}{p_2}\times \dots \frac{p_k-1}{p_k}=n\times \prod_{i=1}^{k}(1-\frac{1}{p_i})

对于 nn 的所有质因子 pip_i,在 1∼n1\sim n 范围内 pip_i 的倍数有 npi\frac{n}{p_i} 个。
那么对于 nn 的两个质因子 p,qp,q,根据容斥,1∼n1\sim n 范围内含质因子 pp 或 qq 的数的个数为 np+nq−npq\frac{n}{p}+\frac{n}{q}-\frac{n}{pq}。
不含质因子 pp 或 qq 的数的个数为 n−np−nq+npq=n×(1−1p−1q+1pq)=n(1−1p)(1−1q)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}),将公式扩展到所有质因子 pip_i 即可得证。

故在分解质因数时即可求出 φ\varphi,时间复杂度 O(n)\mathcal O(\sqrt n)。

1
2
3
4
5
6
7
8
9
10
11
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;
}

求区间内的欧拉函数

  1. 暴力:

代码见求单个数的欧拉函数,时间复杂度 O(nn)\mathcal O(n\sqrt n)。

  1. 埃氏筛:

时间复杂度 O(nlog⁡n)\mathcal O(n\log n)。

1
2
3
4
5
6
7
8
9
10
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 ;
}
  1. 线性筛:

时间复杂度 O(n)\mathcal O(n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 ;
}

题目:

莫比乌斯函数

定义:若根据唯一分解定理使正整数 n=p1c1p2c2…pkckn=p_1^{c_1}p_2^{c_2}\dots p_k^{c_k},则有:

μ(n)={0,∃i∈[1,k],ci>11,m≡0(mod2),∀i∈[1,m],ci=1−1,m≡1(mod2),∀i∈[1,m],ci=1\mu(n)= \begin{cases} 0,\exists i \in [1,k],c_i > 1\\ 1,m\equiv 0\pmod 2,\forall i \in [1,m],c_i=1\\ -1,m\equiv 1\pmod 2,\forall i \in [1,m],c_i=1 \end{cases}

特别地,μ(1)=1\mu(1)=1。

求单个值的莫比乌斯函数

  1. 质因数分解:

时间复杂度 O(n)\mathcal{O}(\sqrt n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}

求区间内的莫比乌斯函数

  1. 埃氏筛:

先初始化 ∀i∈[1,n],μ(i)=1\forall i\in [1,n],\mu(i)=1,显然对于质数 nn 有 μ(n)=−1\mu(n)=-1,对于 nn 的倍数,若 n2∣knn^2\mid kn,则说明出现了 ci>1c_i > 1 的情况,μ(kn)=0\mu(kn)=0,反之则 μ(kn)=−μ(kn)\mu(kn)=-\mu(kn)。

时间复杂度 O(nlog⁡log⁡n)\mathcal{O}(n\log \log n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 ;
}
  1. 线性筛:

对于质数 nn 及每一个被遍历到的合数 n×vin\times v_i,若其出现 ci>1c_i > 1,则停止遍历,否则 μ(n×vi)=−μ(n)\mu(n\times v_i)=-\mu(n)。

时间复杂度 O(n)\mathcal{O}(n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 ;
}

同余

前置知识:

  1. 取模的定义式:

a mod p={a−⌊ap⌋×p,a≥0−(−a mod p),a<0a\bmod p= \begin{cases} a-\lfloor \frac{a}{p} \rfloor \times p,a\geq 0\\ -(-a\bmod p),a<0 \end{cases}

定义:若 x mod p=y mod px\bmod p=y\bmod p,则称 x,yx,y 模 pp 同余,记作 x≡y(modp)x\equiv y\pmod p。

性质:

  1. 自反性:x≡x(modp)x\equiv x\pmod p。

  2. 对称性:若 x≡y(modp)x\equiv y\pmod p,则 y≡x(modp)y\equiv x\pmod p。

  3. 传递性:若 x≡y(modp)x\equiv y\pmod p 且 y≡z(modp)y\equiv z\pmod p,则 x≡z(modp)x\equiv z\pmod p。

  4. 同余式相加性:若 x≡y(modp)x\equiv y\pmod p 且 a≡b(modp)a\equiv b\pmod p,则 (x±a)≡(y±b)(modp)(x\pm a)\equiv (y\pm b)\pmod p。

  5. 同余式相乘性:若 x≡y(modp)x\equiv y\pmod p 且 a≡b(modp)a\equiv b\pmod p,则 ax≡by(modp)ax\equiv by\pmod p。

乘法逆元

前置知识:

  1. 费马小定理:若 pp 为质数且 a⊥pa\perp p,则 ap≡a(modp)a^p\equiv a\pmod p。

定义:若 a⊥pa\perp p 且 xx 为 ax≡1(modp)ax\equiv 1\pmod p 的解,则称 xx 为 aa 模 pp 的乘法逆元,记作 a−1(modp)a^{-1}\pmod p。

求单个值的乘法逆元

若 a⊥̸pa\not \perp p,则不存在 aa 模 pp 的乘法逆元。

  1. 快速幂:若 pp 为质数,且 a⊥pa\perp p,根据费马小定理,可知 aa 模 pp 的乘法逆元为 ap−2 mod pa^{p-2}\bmod p。

由费马小定理可知 ap−1≡1(modp)a^{p-1}\equiv 1\pmod p。
而我们要求 ax≡1(modp)ax\equiv 1\pmod p 的解,由传递性可得:

ax≡ap−1(modp)x≡ap−2(modp)\begin{aligned} ax\equiv a^{p-1}\pmod p\\ x\equiv a^{p-2}\pmod p \end{aligned}

得证。

  1. 扩展欧几里得算法:将方程改写为 ax+py=1ax+py=1,使用扩展欧几里得算法求出 xx 即可。

题目:

求区间内的乘法逆元

  1. 暴力+快速幂:

仅适用于 pp 为质数且 a⊥pa\perp p 的情况,时间复杂度 O(nlog⁡p)\mathcal{O}(n\log p)。

  1. 暴力+扩展欧几里得算法:

代码见扩展欧几里得算法,时间复杂度 O(nlog⁡p)\mathcal{O}(n\log p)。

  1. 线性递推:

invi=−⌊pi⌋×invp mod i mod pinv_i=-\lfloor \frac{p}{i} \rfloor \times inv_{p\bmod i}\bmod p,特别地,inv1=1inv_1=1。

设 p=k×i+rp=k\times i+r,其中 ii 为当前的数,kk 为 ⌊pi⌋\lfloor \frac{p}{i} \rfloor,rr 为 p mod ip\bmod i。

p≡0(modp)k×i+r≡0(modp)\begin{aligned} p \equiv 0 \pmod p\\ k\times i+r \equiv 0 \pmod p \end{aligned}

两边同乘 i−1r−1i^{-1}r^{-1} 得:

k×r−1+i−1≡0(modp)i−1≡−k×r−1(modp)i−1≡−⌊pi⌋×(p mod i)−1(modp)\begin{aligned} k\times r^{-1}+i^{-1} \equiv 0 \pmod p\\ i^{-1} \equiv -k\times r^{-1}\pmod p\\ i^{-1} \equiv -\lfloor \frac{p}{i} \rfloor \times {(p\bmod i)}^{-1} \pmod p \end{aligned}

故递推即可,得证。

时间复杂度 O(n)\mathcal{O}(n)。

1
2
inv[1]=1;
F(i,2,n) inv[i]=(p-p/i)*inv[p%i]%p;

题目:

求区间内阶乘的乘法逆元

  1. 线性递推:

facinvi=facinvi+1×(i+1)facinv_i=facinv_{i+1}\times (i+1),特别地,facinvn=invn! mod pfacinv_n=inv_{n!\bmod p}。

∵facinvi+1=1(i+1)!\because facinv_{i+1}=\frac{1}{(i+1)!}
∴facinvi+1×(i+1)=1i!=facinvi\therefore facinv_{i+1}\times (i+1)=\frac{1}{i!}=facinv_i
得证。

时间复杂度 O(n)\mathcal{O}(n)。

欧拉定理

前置知识:

  1. 同余类:∀a∈[0,m−1]\forall a\in[0,m-1],集合 {a+km}(k∈Z)\{a+km\}(k\in \mathbb{Z}) 的所有数模 mm 同余,余数均为 aa,则称该集合为一个模 mm 的同余类,记为 a‾\overline{a}。

  2. 完全剩余系:mm 个模 mm 的同余类 i‾(i∈[0,m−1])\overline{i} (i\in[0,m-1]) 所构成的集合称为完全剩余系。

  3. 简化剩余系:φ(m)\varphi(m) 个与 mm 互质的数的同余类所构成的集合称为简化剩余系。

  4. 费马小定理:见乘法逆元。

定义:若 a⊥pa\perp p,则 aφ(p)≡1(modp)a^{\varphi(p)}\equiv 1\pmod p。

扩展欧拉定理

ab≡{ab mod φ(p),a⊥pab,a⊥̸p,b<φ(p)ab mod φ(p)+φ(p),a⊥̸p,b≥φ(p)(modp)a^b\equiv \begin{cases} a^{b\bmod \varphi(p)},a\perp p\\ a^b,a\not \perp p,b<\varphi(p)\\ a^{b\bmod \varphi(p)+\varphi(p)},a\not \perp p,b\geq \varphi(p) \end{cases} \pmod p

题目:

扩展欧几里得算法

前置知识:

  1. 欧几里得算法:见求最大公约数。

  2. 裴蜀定理(Bézout 定理):∀a,b∈Z,∃x,y∈Z,ax+by=gcd⁡(a,b)\forall a,b\in \mathbb{Z},\exists x,y\in \mathbb{Z},ax+by=\gcd(a,b)。

在欧几里得算法的最后一步,即 b=0b=0 时,显然存在 x=1,y=0x=1,y=0 使 a×1+0×0=gcd⁡(a,0)a\times 1+0\times 0=\gcd(a,0)。
考虑当 b>0b>0 时,gcd⁡(a,b)=gcd⁡(b,a mod b)\gcd(a,b)=\gcd(b,a\bmod b),设存在一对整数 x,yx,y 使得 gcd⁡(b,a mod b)=bx+(a mod b)y\gcd(b,a\bmod b)=bx+(a\bmod b)y。
由取模的定义式,可转化 bx+(a mod b)y=bx+(a−b⌊ab⌋)y=ay+b(x−⌊ab⌋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′=y,y′=x−⌊ab⌋yx^{\prime}=y,y^{\prime}=x-\lfloor \frac{a}{b} \rfloor y 时,有 ax′+by′=gcd⁡(a,b)ax^{\prime}+by^{\prime}=\gcd(a,b),对递归过程使用数学归纳法即可得证。

对于求 ax+by=gcd⁡(a,b)ax+by=\gcd(a,b) 中 x,yx,y 的值,由裴蜀定理的证明中可知仅需要在欧几里得算法中保存 x,yx,y 即可。

1
2
3
4
5
6
7
8
9
10
11
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;
}

题目:

中国剩余定理

前置知识:

  1. 乘法逆元:见乘法逆元。

若 p1,p2,…,pnp_1,p_2,\dots,p_n 两两互质,求解方程组:

{x≡a1(modp1)x≡a2(modp2)⋮x≡an(modpn)\begin{cases} x\equiv a_1\pmod {p_1}\\ x\equiv a_2\pmod {p_2}\\ \vdots \\ x\equiv a_n\pmod {p_n} \end{cases}

设 m=∏i=1npim=\prod_{i=1}^{n}{p_i},Mi=mpiM_i=\frac{m}{p_i},tit_i 为 MiM_i 模 pip_i 的乘法逆元,则 x=∑i=1naiMiti mod mx=\sum_{i=1}^{n}{a_iM_it_i}\bmod m。

∵Mi\because M_i 为除 pip_i 外所有模数的倍数且 p1,p2,…,pnp_1,p_2,\dots,p_n 两两互质。
∴∀k≠i,akMktk≡0(modpk)\therefore \forall k\neq i,a_kM_kt_k\equiv 0\pmod {p_k}
∵ti≡(Mi)−1(modpi)\because t_i\equiv(M_i)^{-1}\pmod {p_i}
∴aiMiti≡ai(modpi)\therefore a_iM_it_i\equiv a_i\pmod {p_i}
由同余式相加性且 m=∏i=1npim=\prod_{i=1}^{n}{p_i} 可知 xx 在展开之后即为 ∑i=1naiMiti mod m\sum_{i=1}^{n}{a_iM_it_i}\bmod m,得证。

时间复杂度 O(nlog⁡p)\mathcal{O}(n\log p)。

1
2
3
4
5
6
7
8
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;
}

题目:

扩展中国剩余定理

前置知识:

  1. 扩展欧几里得算法:见扩展欧几里得算法。

若 p1,p2,…,pnp_1,p_2,\dots,p_n 不保证两两互质,则上述结论不成立,需要另外一种解法。

考虑 n=2n=2 的情况,可转化为不定方程 x=kp1+a1=bp2+a2,k,b∈Zx=kp_1+a_1=bp_2+a_2,k,b\in \mathbb{Z},则有 kp1−bp2=a2−a1kp_1-bp_2=a_2-a_1。

若 a2−a1∤gcd⁡(p1,p2)a_2-a_1 \nmid \gcd(p_1,p_2),则无解,反之可用扩展欧几里得算法求出一组解 (k,b)(k,b)。

则 x≡kp1+a1(modlcm⁡(p1,p2))x\equiv kp_1+a_1\pmod {\operatorname{lcm} (p_1,p_2)}。

扩展到 n≠2n\neq 2 的情况,仅需要依次求解即可。

时间复杂度 O(nlog⁡n)\mathcal{O}(n\log n)。

1
2
3
4
5
6
7
8
9
10
11
12
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;
}

题目:

组合

加法原理 乘法原理

加法原理(分类):一个问题有 nn 类方法,每个类别有 aia_i 个不同的方法,那么解决此问题有 a1+a2+⋯+ana_1+a_2+\dots+a_n 个方法。

乘法原理(分布):一个问题有 nn 个方法,每个方法有 aia_i 个不同的方式,那么解决此问题的方式个数为 a1×a2×⋯×ana_1\times a_2\times \dots \times a_n。

容斥原理

当 n=2n=2 时,∣A∪B∣=∣A∣+∣B∣−∣A∩B∣|A\cup B|=|A|+|B|-|A\cap B|

当 n=3n=3 时,∣A∪B∪C∣=∣A∣+∣B∣+∣C∣−∣A∩B∣−∣A∩C∣−∣B∩C∣+∣A∩B∩C∣|A\cup B\cup C|=|A|+|B|+|C|-|A\cap B|-|A\cap C|-|B\cap C|+|A\cap B\cap C|

通项式:∣⋃i=1nAi∣=∑∅≠J=⊆{1,2,…,n}(−1)∣J∣−1∣⋂j∈JAj∣|\bigcup_{i=1}^{n}A_i|=\sum_{\varnothing \neq J=\subseteq\{1,2,\dots,n\}}(-1)^{|J|-1}|\bigcap_{j\in J}A_j|

德摩根定律

A∪B‾=A‾∩B‾\overline{A\cup B}=\overline{A}\cap \overline{B},A∩B‾=A‾∪B‾\overline{A\cap B}=\overline{A}\cup \overline{B}

简记:交之补等于补之并,并之补等于补之交。

推论:∣⋂i=1nAi‾∣=∑∅≠J⊆{1,2,…,n}(−1)∣J∣∣⋂j∈JAj∣|\bigcap_{i=1}^{n}\overline{A_i}|=\sum_{\varnothing \neq J\subseteq \{1,2,\dots,n\}}(-1)^{|J|}|\bigcap_{j\in J} A_j|

∣⋃i=1nAi∣=∑∅≠J=⊆{1,2,…,n}(−1)∣J∣−1∣⋂j∈JAj∣∣⋂i=1nAi‾∣=∑∅≠J⊆{1,2,…,n}(−1)∣J∣∣⋂j∈JAj∣∣⋂i=1nAi∣=∑∅≠J⊆{1,2,…,n}(−1)∣J∣∣⋂j∈JAj‾∣\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}

排列数 组合数

排列数:Ank=n!(n−k)!A_{n}^{k}=\frac{n!}{(n-k)!}

组合数:Cnk=(nk)=Ankk!=n!(n−k)!k!=n×(n−1)×⋯×(n−k+1)k!=∏i=0k−1(n−i)k!C_{n}^{k}=\binom{n}{k}=\frac{A_{n}^{k}}{k!}=\frac{n!}{(n-k)!k!}=\frac{n\times(n-1)\times \dots \times (n-k+1)}{k!}=\frac{\prod_{i=0}^{k-1}{(n-i)}}{k!}

特别地,若 k>nk>n 则 Ank=Cnk=0A_{n}^{k}=C_{n}^{k}=0。

性质:

  1. Cn0=1C_{n}^{0}=1,Cn1=nC_{n}^{1}=n,Cn2=n(n−1)2C_{n}^{2}=\frac{n(n-1)}{2}

  2. Cnk=Cnn−kC_{n}^{k}=C_{n}^{n-k}

  3. Cnk=Cn−1k+Cn−1k−1C_{n}^{k}=C_{n-1}^{k}+C_{n-1}^{k-1}

  4. ∑i=0nCni=2n\sum_{i=0}^{n}C_{n}^{i}=2^n

求组合数

  1. 暴力:
1
2
3
4
5
6
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;
}

时间复杂度 O(Tn)\mathcal{O}(Tn),但适用性极差(易爆 long long)。

  1. 递推预处理:

Ci,j={1,j=0Ci−1,j+Ci−1,j−1,otherwiseC_{i,j}= \begin{cases} 1,j=0\\ C_{i-1,j}+C_{i-1,j-1},\text{otherwise} \end{cases}

由性质 33 得证。

1
2
3
4
5
6
7
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 ;
}

时间复杂度 O(n2+T)\mathcal{O}(n^2+T)。

  1. 预处理阶乘+逆元:

这里使用了快速幂求逆元。

1
2
3
4
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;
}

时间复杂度 O(n+Tlog⁡p)\mathcal{O}(n+T\log p)。

  1. 卢卡斯定理:

见卢卡斯定理,仅限 pp 为质数时适用,时间复杂度 O(p+T×log⁡n)\mathcal{O}(p+T\times \log n)。

  1. 扩展卢卡斯定理:

当 pp 不为质数时也适用,时间复杂度 O(p+Tlog⁡p)\mathcal{O}(p+T\log p)。

二项式定理

(x+y)n=Cn0xny0+Cn1xn−1y1+⋯+Cnnx0yn=∑i=0nCnixn−iyi(x+y)^{n}=C_{n}^{0}x^ny^0+C_{n}^{1}x^{n-1}y^{1}+\dots+C_{n}^{n}x^0y^n=\sum_{i=0}^{n}C_{n}^{i}x^{n-i}y^i

对于每一个 (x+y)(x+y),显然要么选 xx,要么选 yy。
若有 kk 个 (x+y)(x+y) 选择 yy,则有 n−kn-k 个选择 xx,由于要选取 kk 个 (x+y)(x+y),故系数为 CnkC_{n}^{k}。
因为 kk 为分类,所以利用加法原理,得证。

计数技巧

等价替代

对于某些计数题,正面解决可能会很困难,这时可以用一些方法将问题转化为另一种更为容易计算的问题。

捆绑法

若要求某些物品相邻,则可将所需相邻的物品看做一个整体,然后计算排列,再分别计算每个整体内的排列相乘。

例题:有 ABCDE\text{ABCDE} 五种物品,其中要求 AB\text{AB} 相邻,CD\text{CD} 相邻,求排列方案数。

可先将 AB\text{AB} 和 CD\text{CD} 看作一个整体,然后对剩下的 33 个物品进行排列,有 A33=6A_{3}^{3}=6 种排列方案。
然后再计算各个整体内的排列,A22=2A_{2}^{2}=2 种。
故共有 2×A22×A33=242\times A_{2}^{2}\times A_{3}^{3}=24 种排列方案。

插空法

若要求某些物品两两不相邻,则可先将其它的物品排好,然后再从空当中插入,分别计算排列后相乘。

例题:有 ABCDEFG\text{ABCDEFG} 其中物品,其中要求 ABC\text{ABC} 两两不相邻,求排列方案数。

先对其它 44 种物品进行排列,有 A44=24A_{4}^{4}=24 种方案。
然后将剩下 33 种物品插入到其中的 55 个空当中,有 A53=60A_{5}^{3}=60 种方案,故共有 A44×A53=1440A_{4}^{4}\times A_{5}^{3}=1440 种排列方案。

隔板法

至少分配问题和不定方程整数解问题可转化为关于插板的组合问题。

例题 11:将 nn 个物品分给 kk 个人,要求每个人至少被分配到一个,求方案数。

将 nn 件物品排成一行,中间有 k−1k-1 个隔板,表示每个人分到的部分,而 k−1k-1 个隔板只能插入到 n−1n-1 个空当中,故方案数为 Cn−1k−1C_{n-1}^{k-1}。

例题 22:将例题 11 的限制改为“允许有人被分配到 00 个”,求方案数。

可将题意抽象为数学模型,求方程 ∑i=1kxi=n\sum_{i=1}^{k}x_i=n 的解,其中 xi≥1x_i\geq 1。
若改限制为 x≥0x\geq 0,则设 yi=xi+1y_i=x_i+1,转化为 ∑i=1k=n+k\sum_{i=1}^{k}=n+k。
再结合上题的解,即可求出方案数为 Cn+k−1k−1C_{n+k-1}^{k-1}。

改变计数目标

对于某些计数题,直接解决可能会很困难,可以用减法原理或容斥原理等内容转化为容易求的问题。

改变枚举顺序

对于某些计数题,直接枚举只能拿到暴力分,可以改变枚举顺序使其更容易计算。

例题:求 ∑i=1n∑j=1nmax⁡(i,j)\sum_{i=1}^{n}\sum_{j=1}^{n}\max(i,j)。

∑i=1n∑j=1nmax⁡(i,j)=∑k=1nk∑i=1n∑j=1n[max⁡(i,j)=k]=∑k=1nk(2k−1)=2∑k=1nk2−(n+1)n2=4n3+3n2−n6\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}

多重集的排列组合数

多重集:指包含重复元素的广义集合。

多重集的排列数

设 S={n1a1,n2a2,…,nkak}S=\{n_1a_1,n_2a_2,\dots,n_ka_k\} 为多重集,则 SS 的全排列个数为

(∑i=1ki)!∏i=1kni!\frac{(\sum_{i=1}^{k} i)!}{\prod_{i=1}^{k}n_i!}

多重集的组合数

设 S={n1a1,n2a2,…,nkak}S=\{n_1a_1,n_2a_2,\dots,n_ka_k\} 为多重集,从 SS 中取出 r(r≤min⁡(ni))r(r\leq \min(n_i)) 个元素组成一个多重集,不考虑元素顺序,产生不同的多重集的数量为

Ck+r−1k−1C_{k+r-1}^{k-1}

设对于每一个 aia_i 选取 xix_i 个,则问题可转化为 ∑i=1kxi=r(xi≥0)\sum_{i=1}^{k}x_i=r(x_i\geq 0) 的不定方程。
用隔板法求解即可。

卢卡斯定理

模数 pp 必须为质数。

Cnm mod p=Cnpmp×Cn mod pm mod p mod pC_{n}^{m}\bmod p=C_{\frac{n}{p}}^{\frac{m}{p}}\times C_{n\bmod p}^{m\bmod p}\bmod p

其中对于左半部分进行递归,右半部分直接进行计算,因为 n mod p,m mod p∈[0,p−1]n\bmod p,m\bmod p\in [0,p-1]。

时间复杂度 O(p+T×log⁡n)\mathcal{O}(p+T\times \log n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);
}

卡特兰数

定义:一种常出现于各种计数问题的数列,记作 HnH_n,特别地,H0=H1=1H_0=H_1=1。

卡特兰数列:

nn 00 11 22 33 44 55 66 …\dots
HnH_n 11 11 22 55 1414 4242 132132 ⋯\cdots

常见题型

  1. nn 个左括号和 nn 个右括号组成的合法括号序列的数量?HnH_n。
  2. 入栈序列为 1,2,…,n1,2,\dots,n 的合法出栈序列数量?HnH_n。
  3. nn 个节点构成的不同的二叉树的数量?HnH_n。
  4. 只能向上或向右走,能从 (0,0)(0,0) 走到 (n,n)(n,n) 且不接触直线 y=xy=x 的路线的数量?2Hn−12H_{n-1}。
  5. 只能向上或向右走,能从 (0,0)(0,0) 走到 (n,n)(n,n) 且不穿过直线 y=xy=x 的路线的数量?Hn+1H_{n+1}。

求卡特兰数

以下所有公式均有 i≥2i\geq 2。

  1. 递推:

Hi=Hi−1(4i−2)i+1H_i=\frac{H_{i-1}(4i-2)}{i+1}

  1. 组合通式:

Hi=C2iii+1H_i=\frac{C_{2i}^{i}}{i+1}

Hi=C2ii−C2ii−1H_i=C_{2i}^{i}-C_{2i}^{i-1}

Hi=∑j=1iHj−1Hi−jH_i=\sum_{j=1}^{i}H_{j-1} H_{i-j}