数论基础

根据心情在这里收录一些数论知识。

这应该是对数论小白极友好的数论入门博客了。(如果你不按顺序看的话我可不保证看得懂qwq)

随时更新。

基础中的基础

如果想要获得良好的阅读体验,以下一点符号有必要知道:

  1. a ∣ b a|b ab,可以理解为 a a a 整除 b b b a a a b b b 的因子
  2. gcd ⁡ \gcd gcd,表示最大公约数,用法为 gcd ⁡ ( a , b ) \gcd(a,b) gcd(a,b),有时也缩写成 ( a , b ) (a,b) (a,b)
  3. l c m lcm lcm,表示最小公倍数,用法为 l c m ( a , b ) lcm(a,b) lcm(a,b),有时写缩写成 [ a , b ] [a,b] [a,b]
  4. ( l , r ) (l,r) (l,r) [ l , r ] [l,r] [l,r] 有时也分别表示开区间和闭区间,这个结合情况分析
  5. n ! n! n! 表示 n n n 的阶乘,即 n ! = 1 × 2 × 3 × . . . × ( n − 1 ) × n n!=1\times 2 \times 3 \times ... \times (n-1) \times n n!=1×2×3×...×(n1)×n
  6. 要知道集合的基本知识,比如说 ∈ , Z , Z ∗ , p r i m e \in,Z,Z^*,prime ,Z,Z,prime 的意思。
  7. 请务必带上脑子再往下看qwq

排列组合

全排列

n n n 个数的全排列是指:这 n n n 个数的所有不同的排列。

比如说,三个数 1 , 2 , 3 1,2,3 1,2,3 的全排列为:
1 , 2 , 3 1,2,3 1,2,3
1 , 3 , 2 1,3,2 1,3,2
2 , 1 , 3 2,1,3 2,1,3
2 , 3 , 1 2,3,1 2,3,1
3 , 1 , 2 3,1,2 3,1,2
3 , 2 , 1 3,2,1 3,2,1

一个组合数学的基础知识: n n n 个数的全排列数量为 n ! n! n!,比如上面的, 3 3 3 个数的全排列数量就有 1 × 2 × 3 = 6 1\times 2 \times 3=6 1×2×3=6 种。

证明:

f [ i ] f[i] f[i] i i i 个数的全排列数量。

那么显然有: f [ i ] = f [ i − 1 ] × i f[i]=f[i-1]\times i f[i]=f[i1]×i,因为考虑在 i − 1 i-1 i1 个数的全排列里面插入 i i i 这个数,一共有 i i i 个位置可以插,所以方案数为 f [ i − 1 ] × i f[i-1] \times i f[i1]×i

所以 i i i 个数的全排列方案数为 i ! i! i!

组合数

组合数详解

卢卡斯定理

卢卡斯定理

卡特兰数

卡特兰数详解

同余

这里的同余,是指余数相同。

取模

取模运算,表示取某个数除以另一个数的余数。

比如说, a   m o d   b = c a\bmod b =c amodb=c,就是 a a a b b b 等于 c c c,这个柿子可以理解为 a a a 除以 b b b c c c

取模运算的运算等级和乘除法相同,也就是说,在一条只有乘、除、取模运算的柿子中,我们需要从左到右依次进行计算。

运算性质

1、 不满足交换律,结合律,分配率,证明很显然,随手就能找出例子。

2、 ( a   m o d   p ) × ( b   m o d   p )   m o d   p = a × b   m o d   p (a\bmod p)\times (b\bmod p) \bmod p=a\times b \bmod p (amodp)×(bmodp)modp=a×bmodp

这个不难证明,但首先要知道, p p p 的倍数模 p p p 都等于 0 0 0

a = x 1 p + y 1 , b = x 2 p + y 2   ( y 1 , y 2 < p ) a=x_1p+y_1,b=x_2p+y_2~(y_1,y_2<p) a=x1p+y1,b=x2p+y2 (y1,y2<p),那么上面的柿子等于:
( ( x 1 p + y 1 )   m o d   p ) × ( ( x 2 p + y 2 )   m o d   p )   m o d   p = ( ( x 1 p + y 1 ) × ( x 2 p + y 2 ) )   m o d   p y 1 y 2   m o d   p = ( x 1 x 2 p 2 + x 1 y 2 p + y 1 x 2 p + y 1 y 2 )   m o d   p y 1 y 2   m o d   p = y 1 y 2   m o d   p \begin{aligned} ((x_1p+y_1)\bmod p) \times ((x_2p+y_2)\bmod p) \bmod p&=((x_1p+y_1)\times (x_2p+y_2)) \bmod p\\ y_1y_2\bmod p&=(x_1x_2p^2+x_1y_2p+y_1x_2p+y_1y_2)\bmod p\\ y_1y_2\bmod p&=y_1y_2\bmod p\\ \end{aligned} ((x1p+y1)modp)×((x2p+y2)modp)modpy1y2modpy1y2modp=((x1p+y1)×(x2p+y2))modp=(x1x2p2+x1y2p+y1x2p+y1y2)modp=y1y2modp

同余

隆重请出同余号—— ≡ \equiv

这个符号还表示恒等于,但是这里不多做讨论。

这个运算符表示等式左右在模某个数的意义下相等,标准用法:
a ≡ b ( m o d p ) a\equiv b \pmod p ab(modp)

同余号和后面的 ( m o d p )    \pmod p~~ (modp)   是标配,表示 a a a b b b 在模 p p p 意义下相等。

运算性质

1、 如果有 a ≡ b ( m o d p ) , c ≡ d ( m o d p ) a\equiv b \pmod p,c\equiv d \pmod p ab(modp),cd(modp),那么有 a + c ≡ b + d ( m o d p ) a+c\equiv b+d \pmod p a+cb+d(modp)
2、 如果有 a ≡ b ( m o d p ) , c ≡ d ( m o d p ) a\equiv b \pmod p,c\equiv d \pmod p ab(modp),cd(modp),那么有 a c ≡ b d ( m o d p ) ac\equiv bd \pmod p acbd(modp)

这两条很显然,就不证明了。

3、 如果有 a c ≡ b c ( m o d p ) ac\equiv bc \pmod p acbc(modp),那么有 a ≡ b ( m o d p d ) a\equiv b \pmod {\frac p d} ab(moddp),其中 d = gcd ⁡ ( c , p ) d=\gcd(c,p) d=gcd(c,p)

证明:

∵ a c ≡ b c ( m o d p ) \because ac\equiv bc \pmod p acbc(modp)
∴ a c − b c ≡ 0 ( m o d p ) \therefore ac-bc\equiv 0 \pmod p acbc0(modp)
p ∣ ( a c − b c ) p|(ac-bc) p(acbc)
∴ p ∣ c ( a − b ) \therefore p|c(a-b) pc(ab)
∴ p d ∣ c d ( a − b ) \therefore\frac p d|\frac c d(a-b) dpdc(ab)
∵ ( p d , c d ) = 1 \because (\frac p d,\frac c d)=1 (dp,dc)=1
∴ p d ∣ ( a − b ) \therefore \frac p d|(a-b) dp(ab)
a ≡ b ( m o d p d ) a \equiv b \pmod {\frac p d} ab(moddp)

逆元

我们知道,取模操作不能涉及小数,否则没有意义。

比如说,给一个柿子: 5 ÷ 3 5\div 3 5÷3,大家都知道这个东西商为 1 1 1,余数为 2 2 2,也就是:
5 ÷ 3 = 1 ⋯ 2 5\div 3 = 1 \cdots2 5÷3=12

假如我们引入了小数,那么柿子可以是:
5 ÷ 3 = 1.2 ⋯ 1.4 5\div 3 = 1.2 \cdots 1.4 5÷3=1.21.4

不仅是这样,还可以有很多奇奇怪怪的变化,那么余数就失去了其意义。

于是得到结论:取模操作不能涉及小数

那么怎么处理取模运算中的除法呢?

我们学过一个叫倒数的东西:对于一个数 a a a,假如存在数 b b b 满足 a b = 1 ab=1 ab=1,那么称 b b b a a a 的倒数。

以及我们知道倒数有个优秀的性质:除以一个数等于乘这个数的倒数。

于是取模运算中,也发明了这样一个东西,其名曰——逆元

对于一个数 x x x,假如存在 a x ≡ 1 ( m o d p ) ax\equiv 1 \pmod p ax1(modp),那么称 a a a x x x 在模 p p p 意义下的逆元。

于是在取模意义下,所有除以 x x x 的操作都可以换成乘以 a a a

存在性判断

当满足 ( a , p ) = 1 (a,p)=1 (a,p)=1 时, a a a 在模 p p p 意义下才有逆元。

证明在后面的扩展欧几里得算法里。

费马小定理

对于质数 p p p,有 a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1 \pmod p ap11(modp),其中 a a a 是一个正整数。

证明

假设现在有一个序列 1 , 2 , 3 , 4 , . . . , p − 2 , p − 1 1,2,3,4,...,p-2,p-1 1,2,3,4,...,p2,p1

假设将这个序列乘以 a a a,然后对 p p p 取模,那么就变成: a , 2 a , 3 a , . . . , ( p − 1 ) a ( m o d p ) a,2a,3a,...,(p-1)a \pmod p a,2a,3a,...,(p1)a(modp)

可以证明,此时的序列中没有相同的数。


证明: 考虑反证法。

x , y x,y x,y 满足 a x ≡ a y ( m o d p ) ax\equiv ay \pmod p axay(modp) x ≠ y x\neq y x=y

根据同余的运算性质3,此时 ( a , p ) = 1 (a,p)=1 (a,p)=1,所以有 x ≡ y ( m o d p ) x\equiv y \pmod p xy(modp)

但是我们一开始构造的序列中是没有相同的数的,所以 x ≡ y ( m o d p ) x \equiv y \pmod p xy(modp) 不成立。所以,不存在这样的 x , y x,y x,y证毕


因为这个序列有 p − 1 p-1 p1 项,在模 p p p 意义下没有相同的数,且这里面没有 p p p 的倍数,所以这个序列是 1 1 1 ~ p − 1 p-1 p1 的一个排列。

那么有
1 × 2 × 3 × . . . × ( p − 1 ) ≡ a × 2 a × 3 a × . . . × ( p − 1 ) a ( m o d p ) 1 × 2 × 3 × . . . × ( p − 1 ) ≡ 1 × 2 × 3 × . . . × ( p − 1 ) × a p − 1 ( m o d p ) 1 ≡ a p − 1 ( m o d p ) \begin{aligned} 1\times 2 \times 3 \times ... \times(p-1)& \equiv a\times 2a \times 3a \times ... \times (p-1)a \pmod p\\ 1\times 2 \times 3 \times ... \times(p-1)& \equiv 1\times 2 \times 3 \times ... \times (p-1) \times a^{p-1} \pmod p\\ 1&\equiv a^{p-1} \pmod p\\ \end{aligned} 1×2×3×...×(p1)1×2×3×...×(p1)1a×2a×3a×...×(p1)a(modp)1×2×3×...×(p1)×ap1(modp)ap1(modp)

得证

应用

根据费马小定理,有
a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1 \pmod p ap11(modp)
其中 p ∈ p r i m e p\in prime pprime,变化一下:
a p − 2 × a ≡ 1 ( m o d p ) a^{p-2} \times a \equiv 1 \pmod p ap2×a1(modp)

那么可以知道, a p − 2 a^{p-2} ap2 就是 a a a 在模 p p p 意义下的逆元。

费马小定理(我觉得)最重要的用法就是这个了,以后也会广泛用到。

要注意,如果只是满足 ( a , p ) = 1 (a,p)=1 (a,p)=1 而不满足 p ∈ p r i m e p\in prime pprime,那么即使 a a a 在模 p p p 意义下有逆元,也不能用费马小定理来求。

BSGS算法

Baby-step Giant-step 算法,是用来求解这个方程的: a x ≡ n ( m o d p ) a^x\equiv n\pmod p axn(modp),其中 p p p 是质数。

由于 x x x 一定在 [ 0 , p − 2 ] [0,p-2] [0,p2] 内,设 x = A ⌈ p ⌉ − B x=A\lceil\sqrt p\rceil-B x=Ap B,其中 B ∈ [ 0 , ⌈ n ⌉ ) , A ∈ [ 1 , ⌈ n ⌉ ] B\in[0,\lceil \sqrt n \rceil),A\in[1,\lceil \sqrt n \rceil] B[0,n ),A[1,n ]

那么有 a A ⌈ p ⌉ − B ≡ n ( m o d p ) ⇒ a A ⌈ p ⌉ ≡ n a B ( m o d p ) a^{A\lceil \sqrt p \rceil-B}\equiv n\pmod p\Rightarrow a^{A\lceil \sqrt p\rceil}\equiv na^B\pmod p aAp Bn(modp)aAp naB(modp)

于是我们可以枚举 B B B,将所有 n a B na^B naB 放到哈希表里面,然后再枚举 A A A,看看哈希表里面是否存在 a A ⌈ p ⌉ a^{A\lceil \sqrt p\rceil} aAp 这个值即可。时间复杂度 O ( p log ⁡ p ) O(\sqrt p\log p) O(p logp)

代码如下:

#include <cstdio>
#include <cstring>
#include <map>
#include <cmath>
#include <algorithm>
using namespace std;

int mod,a,n;
int ksm(int x,long long y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
map<int,int> mp;

int main()
{
	scanf("%d %d %d",&mod,&a,&n);
	int sz=ceil(sqrt(mod));
	int ans=-1;
	for(int i=0;i<sz;i++){
		int x=1ll*n*ksm(a,i)%mod;
		if(!mp.count(x))mp[x]=i;
	}
	for(int i=1;i<=sz;i++){
		int x=ksm(a,1ll*i*sz);
		if(mp.count(x)){ans=i*sz-mp[x];break;}
	}
	if(ans!=-1)printf("%d",ans);
	else puts("no solution");
}

快速幂&快速乘

快速幂

快速乘


欧几里得算法

欧几里得算法


扩展欧几里得算法

扩展欧几里得算法


欧拉定理

欧拉定理


扩展欧拉定理

首先当然是要学了上面的欧拉定理。

欧拉定理只适用于 a a a p p p 互质的情况,而扩展欧拉定理则更加广泛:
a c ≡ { a c   m o d   φ ( p )            ( gcd ⁡ ( a , b ) = 1 ) a c                         ( gcd ⁡ ( a , p ) ≠ 1 , c < φ ( p ) ) a c   m o d   φ ( p ) + φ ( p )     ( gcd ⁡ ( a , p ≠ 1 ) , c ≥ φ ( p ) ) ( m o d p ) a^c\equiv \begin{cases} a^{c\bmod \varphi(p)}~~~~~~~~~~(\gcd(a,b)=1)\\ a^c~~~~~~~~~~~~~~~~~~~~~~~(\gcd(a,p)\neq 1,c< \varphi(p))\\ a^{c\bmod \varphi(p)+\varphi(p)}~~~(\gcd(a,p\neq 1),c\geq \varphi(p)) \end{cases} \pmod p acacmodφ(p)          (gcd(a,b)=1)ac                       (gcd(a,p)=1,c<φ(p))acmodφ(p)+φ(p)   (gcd(a,p=1),cφ(p))(modp)

证明:

第一条就是欧拉定理的简单应用。

第二条没什么应用。

重点是第三条,考虑将 p p p 分解为 p 1 c 1 p 2 c 2 . . . p k c k p_1^{c_1}p_2^{c_2}...p_k^{c_k} p1c1p2c2...pkck,如果能证明 ∀ i ∈ [ 1 , k ] \forall i\in[1,k] i[1,k],都有 a c ≡ a c   m o d   φ ( p ) + φ ( p ) ( m o d p i c i ) a^c\equiv a^{c\bmod \varphi(p)+\varphi(p)} \pmod {p_i^{c_i}} acacmodφ(p)+φ(p)(modpici),而由于 x ≡ y ( m o d m 1 ) x\equiv y\pmod {m_1} xy(modm1) x ≡ y ( m o d m 2 ) x\equiv y\pmod {m_2} xy(modm2) 可以推出 x ≡ y ( m o d m 1 m 2 ) x\equiv y\pmod {m_1m_2} xy(modm1m2),那么即可证得 a c ≡ a c   m o d   φ ( p ) + φ ( p ) ( m o d p ) a^c\equiv a^{c\bmod \varphi(p)+\varphi(p)} \pmod p acacmodφ(p)+φ(p)(modp)

分类讨论一下,若 gcd ⁡ ( a , p i c i ) = 1 \gcd(a,p_i^{c_i})=1 gcd(a,pici)=1,那么显然成立(根据欧拉定理)。

否则, a a a 一定是 p i p_i pi 的倍数,即可以分解成 x × p i x\times p_i x×pi,其中 x x x 不一定与 p i p_i pi 互质,但是这不重要。


引理: φ ( p i c i ) ≥ c i \varphi(p_i^{c_i})\geq c_i φ(pici)ci

证明: 由于 φ ( p i c i ) = ( p i − 1 ) × p i c i − 1 \varphi(p_i^{c_i})=(p_i-1)\times p_i^{c_i-1} φ(pici)=(pi1)×pici1,所以上式等价于 ( p i − 1 ) × p i c i − 1 ≥ c i (p_i-1)\times p_i^{c_i-1}\geq c_i (pi1)×pici1ci

考虑 p i = 2 p_i=2 pi=2 的情况,手玩发现 c i = 1 c_i=1 ci=1 时是满足的,归纳一下 c i > 1 c_i>1 ci>1 时也满足。然后再归纳一下,由于 p i p_i pi 增大时不等式左边增大,右边不变,所以 p i > 2 p_i>2 pi>2 时也满足,证毕。


由于 φ \varphi φ 是积性函数,根据引理,有 c ≥ φ ( p ) ≥ φ ( p i c i ) ≥ c i c\geq \varphi(p)\geq \varphi(p_i^{c_i})\geq c_i cφ(p)φ(pici)ci

又由于 a c ≡ x c p i c a^c\equiv x^cp_i^c acxcpic,所以 p i c i ∣ p i c ∣ a c p_i^{c_i}|p_i^c|a^c picipicac,即 a c ≡ 0 ( m o d p i c i ) a^c\equiv 0\pmod {p_i^{c_i}} ac0(modpici)

φ ( p ) \varphi(p) φ(p) 也是大于等于 c i c_i ci 的,即 a φ ( p ) ≡ 0 ( m o d p i c i ) a^{\varphi(p)}\equiv 0\pmod {p_i^{c_i}} aφ(p)0(modpici)

所以有 a c ≡ a c   m o d   φ ( p ) + φ ( p ) ≡ 0 ( m o d p i c i ) a^c\equiv a^{c\bmod \varphi(p)+\varphi(p)}\equiv 0\pmod {p_i^{c_i}} acacmodφ(p)+φ(p)0(modpici)证毕。


线性方程

定义: 未知数的次数都是 1 1 1 次的方程。

如: 2 x + 3 y + z − 4 = 9 2x+3y+z-4=9 2x+3y+z4=9

假如线性方程中含有 n n n 个未知数,那么至少需要 n n n 条包含这 n n n 个未知数的线性方程才能求出这些未知数。

当然,也会有 n n n 条线性方程也求不出 n n n 个未知数的情况,比如说当 n n n 等于 2 2 2 时,给你这样两个方程:
{ 3 x + 6 y = 6 1 x + 2 y = 2 \begin{cases} 3x+6y=6\\ 1x+2y=2 \end{cases} {3x+6y=61x+2y=2

显然求不出来(指无限解)。

高斯消元

这是一个用来求解线性方程组的算法。

高斯消元


质数

定义: 对于一个数 x x x,假如他只有 1 1 1 和它本身两个因子,那么称这个数为质数。

别名: 素数。

判断是否为质数

暴力

尝试去找这个数的因子。

这个有个优化,我们知道,假如一个数 n n n 拥有因子 a a a,那么他肯定也拥有另一个因子 n a \dfrac n a an,而 a a a n a \frac n a an 这两个数之间至少有一个小于等于 n \sqrt n n ,所以我们只需要在 2 2 2 ~ n \sqrt n n 这个区间内去找有没有因子即可。

代码:

bool prime(int x)
{
	if(x==1)return false;//特判掉1
	for(int i=2;i*i<=x;i++)//枚举2~sqrt(x)
	if(x%i==0)return false;//假如有因子,那么就不是质数
	return true;//假如没有找到因子,那么就是质数
}

费马小定理

我们知道,如果有 p ∈ p r i m e p\in prime pprime,那么对于任意 a ∈ Z ∗ a\in Z^* aZ,都有 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1 \pmod p ap11(modp)

那么对于一个数 x x x,我们随便找几个与 x x x 互质的数,看他们的 x − 1 x-1 x1 次方是否为 1 1 1 即可,假如有一个数的 x − 1 x-1 x1 次方不为 1 1 1,那么 x x x 就不是质数。

但是这是一个看人品的算法,因为有一种叫伪素数的东西。

这种东西他不是素数,但是它可以通过这种费马小定理探测法。伪素数表网上一搜一大堆,这里不列举了。

Miller-Rabin 算法

这虽然也是一个看人品的算法,但是比费马小定理探测法可靠的多。


二次探测定理

具体内容: 假如 p p p 是个质数,那么对于同余方程 x 2 ≡ 1 ( m o d p ) x^2 \equiv 1 \pmod p x21(modp),它的解只有 x 1 = 1 , x 2 = p − 1 x_1=1,x_2=p-1 x1=1,x2=p1

证明: 解一下就好了。
x 2 ≡ 1 ( m o d p ) x 2 − 1 ≡ 0 ( m o d p ) ( x + 1 ) ( x − 1 ) ≡ 0 ( m o d p ) \begin{aligned} x^2&\equiv 1 \pmod p\\ x^2-1&\equiv 0 \pmod p\\ (x+1)(x-1)&\equiv 0 \pmod p\\ \end{aligned} x2x21(x+1)(x1)1(modp)0(modp)0(modp)

所以有 x + 1 ≡ 0 ( m o d p ) x+1\equiv 0 \pmod p x+10(modp) x − 1 ≡ 0 ( m o d p ) x-1\equiv 0 \pmod p x10(modp),解出来就是 x ≡ 1   o r   p − 1 ( m o d p ) x\equiv 1~or~p-1 \pmod p x1 or p1(modp)


回到 Miller-Rabin 算法。

算法流程如下:

  1. 随手选出一个与 x x x 互质的数 a a a
  2. 用费马小定理探测法判断这个 a a a,假如满足 a x − 1 ≡ 1 ( m o d x ) a^{x-1}\equiv 1 \pmod x ax11(modx),进入下一步,否则可以判断出 x x x 不为素数。
  3. 因为 a x − 1 ≡ 1 ( m o d x ) a^{x-1}\equiv 1 \pmod x ax11(modx),根据二次探测定理,假如 x x x 是个质数,那么有 a x − 1 2 ≡ 1   o r   p − 1 ( m o d x ) a^{\frac {x-1} 2} \equiv 1~or~p-1 \pmod x a2x11 or p1(modx),假如 a x − 1 2 a^{\frac {x-1} 2} a2x1 不是 1 1 1 p − 1 p-1 p1,那么 x x x 不为质数。假如 a x − 1 2 a^{\frac {x-1} 2} a2x1 1 1 1 并且 x − 1 2 \frac {x-1} 2 2x1 是个偶数,那么就继续探测 x − 1 4 \frac {x-1} 4 4x1,否则停下。

根据奇奇怪怪的证明,假如一个数 x x x 成功通过了一次 Miller-Rabin 算法,那么它不是质数的可能性降到 1 4 \frac 1 4 41,那么不妨多测几次,假如测 y y y 次,那么它不是质数的可能性就就降到了 1 4 y \frac 1 {4^y} 4y1。(证明?我怎么可能会。)

素数筛法

暴力筛

对于 1 1 1 ~ n n n 的每个数,都判断一下是不是质数。为了保证正确性以及为了方便,采取暴力判断的方式。

代码:

#include <cstdio>

bool prime(int x)
{
	if(x==1)return false;
	for(int i=2;i*i<=x;i++)
	if(x%i==0)return false;
	return true;
}

int main()
{
	for(int i=1;i<=100;i++)
	if(prime(i))printf("%d ",i);
}

时间复杂度: O ( n n ) O(n\sqrt n) O(nn )

优化的暴力筛

对于任意一个数 x x x,都可以表示成 6 n − 5 , 6 n − 4 , 6 n − 3 , 6 n − 2 , 6 n − 1 , 6 n 6n-5,6n-4,6n-3,6n-2,6n-1,6n 6n5,6n4,6n3,6n2,6n1,6n 中的一种,比如说 7 = 2 × 6 − 5 , 21 = 4 × 6 − 3 7=2\times 6 -5,21=4 \times 6 -3 7=2×65,21=4×63

我们发现,假如一个数可以表示成 6 n − 4 , 6 n − 2 6n-4,6n-2 6n4,6n2,那么他一定是 2 2 2 的倍数,不可能是质数。

假如一个数可以表示成 6 n − 3 6n-3 6n3,那么他一定是 3 3 3 的倍数,不可能是质数。

假如一个数可以表示成· 6 n 6n 6n,那么他一定是 6 6 6 的倍数,不可能是质数。

所以,质数都可以表示成 6 n − 5 6n-5 6n5 6 n − 1 6n-1 6n1

那么尝试优化上面的暴力筛:对于一个数 x x x,我们找他的因子的时候,只找质因子,这样的效果是相同的,然后枚举质因子的时候就可以 6 6 6 6 6 6 个跳,而不是 1 1 1 1 1 1 个跳了。

时间复杂度: O ( n 6 ) O(\frac {\sqrt n} 6) O(6n )

埃氏筛

我们知道,对于一个质数 x x x,它的倍数 2 x , 3 x , 4 x , . . . 2x,3x,4x,... 2x,3x,4x,... 肯定都不是质数。

埃氏筛就是用了这样的搞法。

代码:

#include <cstdio>

bool v[110];//记录每个数是否为素数,false为是,true为不是

int main()
{
	for(int i=2;i<=100;i++)
	if(!v[i])
	{
		printf("%d ",i);
		for(int j=2;i*j<=100;j++)
		v[i*j]=true;
	}
}

时间复杂度: O ( n ln ⁡ n ) O(n\ln n) O(nlnn)

证明的话参考调和级数即可。

欧拉筛

埃氏筛还不够优秀,于是欧拉筛出现了。

先贴代码:

#include <cstdio>

bool v[110];
int prime[110],t=0;

int main()
{
	for(int i=2;i<=100;i++)
	{
		if(!v[i])prime[++t]=i;//假如i没有被筛到过,那么记录下来
		for(int j=1;j<=t&&i*prime[j]<=100;j++)
		//枚举一个素数prime[j],筛掉i*prime[j]这个数
		{
			v[i*prime[j]]=true;
			if(i%prime[j]==0)break;//假如prime[j]是i的因子,那么就停下
			//这一步下面会详细讲
		}
	}
	for(int i=1;i<=t;i++)
	printf("%d ",prime[i]);
}

欧拉筛最神的就是这一行:

if(i%prime[j]==0)break;

这样可以保证:对于每个合数,他都只会被自己最小的那个质因子筛掉

简单的证明:

比如说对于一个合数 n n n,假设它最小的质因子是 x x x,以及他还有另外一个质因子 y y y。显然满足 x < y x<y x<y

要筛掉 n n n,有两种情况:

  1. i i i 枚举到 n x \frac n x xn 时, p r i m e [ j ] prime[j] prime[j] 枚举到 x x x
  2. i i i 枚举到 n y \frac n y yn 时, p r i m e [ j ] prime[j] prime[j] 枚举到 y y y

有一个性质: x x x 一定是 n y \frac n y yn 的因子。

那么当 i i i 枚举到 n y \frac n y yn 时, p r i m e [ j ] prime[j] prime[j] 在枚举到 x x x 时就会停下,不会继续枚举到 y y y

因此,第一种情况不可能出现。所以,每个合数只可能被自己最小的质因子筛掉。

于是,时间复杂度: O ( n ) O(n) O(n)


唯一分解定理

对于任意一个正整数 n n n,都可以被唯一地拆成若干个质数相乘的形式,形如: p 1 a 1 p 2 a 2 . . . p m a m p_1^{a_1}p_2^{a_2}...p_m^{a_m} p1a1p2a2...pmam,比如说, 60 = 2 2 × 3 1 × 5 1 60=2^2\times 3^1 \times 5^1 60=22×31×51

这个唯一性过于显然,没有必要证明了。

求因子数

对于一个可以分解为 p 1 a 1 p 2 a 2 . . . p m a m p_1^{a_1}p_2^{a_2}...p_m^{a_m} p1a1p2a2...pmam 的数 n n n,它的因子肯定也可以由 p 1 , p 2 , . . . , p m p_1,p_2,...,p_m p1,p2,...,pm 的若干次方相乘得到,并且对于任意一个因子的一个质因数 p i p_i pi,它在因子中的指数一定不大于在 n n n 中的指数。

那么对于 p i p_i pi,它的指数的取值范围就是 [ 0 , a i ] [0,a_i] [0,ai],所以 n n n 的因子数就是 ( a 1 + 1 ) ( a 2 + 1 ) . . . ( a m + 1 ) (a_1+1)(a_2+1)...(a_m+1) (a1+1)(a2+1)...(am+1)

求因子之和

考虑计算每一个质因子的贡献,用分配率加起来,那么就是:
( p 1 0 + p 1 1 + . . . + p 1 a m ) ( p 2 0 + p 2 1 + . . . + p 2 a m ) . . . ( p m 0 + p 1 m + . . . + p m a m ) (p_1^0+p_1^1+...+p_1^{a_m})(p_2^0+p_2^1+...+p_2^{a_m})...(p_m^0+p_1^m+...+p_m^{a_m}) (p10+p11+...+p1am)(p20+p21+...+p2am)...(pm0+p1m+...+pmam)


中国剩余定理

中国剩余定理


扩展中国剩余定理

扩展中国剩余定理


容斥

这是个极大的版块,不太能讲完,这里就浅浅涉及一些。

据我所知,容斥大概有两种形式。

形式1

定义一个函数 g ( S ) g(S) g(S) 表示集合 S S S 的价值,定义子集和函数 f ( S ) = ∑ T ∈ S g ( T ) f(S)=\sum_{T\in S} g(T) f(S)=TSg(T),假如我们知道了 f f f,可以通过这个柿子得到 g g g
g ( S ) = ∑ S ∈ T ( − 1 ) ∣ S ∣ − ∣ T ∣ f ( T ) g(S)=\sum_{S\in T}(-1)^{|S|-|T|}f(T) g(S)=ST(1)STf(T)

类似的,可以定义超集和函数 f ( S ) = ∑ S ∈ T g ( T ) f(S)=\sum_{S\in T}g(T) f(S)=STg(T),知道 f f f 时就可以通过类似的柿子得到 g g g
g ( S ) = ∑ T ∈ S ( − 1 ) ∣ S ∣ − ∣ T ∣ f ( T ) g(S)=\sum_{T\in S}(-1)^{|S|-|T|}f(T) g(S)=TS(1)STf(T)

很多时候,这个集合 S S S 里面记录的是限制,比如 f ( S ) f(S) f(S) 表示至少满足 S S S 这些限制的情况数量,则 g ( S ) g(S) g(S) 表示恰好满足 S S S 这些限制的情况数量。

至少这个限制大多数时候是比恰好要松的,往往会更好求,此时就可以通过求出 f f f,然后容斥再求出 g g g

形式2

记所有组合对象为 U U U,有若干种属性 1 , 2 , ⋯   , k 1,2,\cdots,k 1,2,,k,每个组合对象拥有一些属性,记 A i A_i Ai 表示所有拥有属性 P i P_i Pi 的对象集合,令 S S S 为包含了任意一些属性的集合,那么有:
∣ ⋃ i ∈ S A i ∣ = ∑ T ∈ S ( − 1 ) ∣ T ∣ − 1 ∣ ⋂ j ∈ T A j ∣ |\bigcup_{i\in S}A_i|=\sum_{T\in S}(-1)^{|T|-1} |\bigcap_{j\in T} A_j| iSAi=TS(1)T1jTAj

显然也可以将并集和交集符号交换一下得到类似的容斥公式。

以这个柿子为例,一个小学就学过的简单容斥问题其实就是它的经典应用:

a a a 个人学FFT, b b b 个人学NTT, c c c 个人学FMT, d d d 个人同时学FFT和NTT, e e e 个人同时学NTT和FMT, f f f 个人同时学FFT和FMT, g g g 个人同时学FFT、NTT和FMT,求有多少个人学了至少一种算法。

众所周知答案是 a + b + c − d − e − f + g a+b+c-d-e-f+g a+b+cdef+g,本质上容斥的过程是:先把所有人算上,然后把重复计算的减掉,再把重复减掉的加上,如此反复直到最后一次计算后没有重复的为止。

看起来这样可以使每个人只被统计一次,如何用数学方法严谨证明一下呢?

对于一个学习了 n n n 个算法的人,他会被统计这么多次:
∑ i = 1 n ( n i ) ( − 1 ) i − 1 \sum_{i=1}^n \binom n i (-1)^{i-1} i=1n(in)(1)i1

其中,假设他学习的算法集合为 S S S,那么它就有 ( n i ) \binom n i (in) 个大小为 i i i 的子集 T T T,贡献的系数为 ( − 1 ) ∣ T ∣ − 1 (-1)^{|T|-1} (1)T1,即 ( − 1 ) i − 1 (-1)^{i-1} (1)i1

推一推:
= − ( ∑ i = 0 n ( n i ) ( − 1 ) i ) + 1 = ( 1 − 1 ) n + 1 = 1 =-\left(\sum_{i=0}^n \binom n i(-1)^i\right)+1=(1-1)^n+1=1 =(i=0n(in)(1)i)+1=(11)n+1=1

这样就证完了,中间用到的是二项式定理。

简单反演

对于一个关系: f n = ∑ a n , i g ( i ) f_n=\sum a_{n,i}g(i) fn=an,ig(i),知道 f f f 求回 g g g 的过程便是反演。

似乎大部分反演的本质就是容斥。

莫比乌斯反演

莫比乌斯反演

当时相当的菜,只会背个定义套套式子,这里写一些其他的东西。

莫比乌斯函数 μ \mu μ 是个相当厉害的容斥系数,还记得在欧拉函数那里看到的一条式子吗?
φ ( n ) = ∑ i ∣ n μ ( i ) n i \varphi(n)=\sum_{i|n} \mu(i)\frac n i φ(n)=inμ(i)in

就以这个为例子,来初步理解一下 μ \mu μ 的容斥意义。

姑且先看看 φ ( n ) \varphi(n) φ(n) 的本质: n n n 以内与 n n n 互质的数的个数。也就有:
φ ( n ) = ∑ i = 1 n [ gcd ⁡ ( i , n ) = 1 ] = ∑ i = 1 n ∑ d ∣ gcd ⁡ ( i , n ) μ ( d ) \begin{aligned} \varphi(n)&=\sum_{i=1}^n [\gcd(i,n)=1]\\ &=\sum_{i=1}^n\sum_{d|\gcd(i,n)}\mu(d) \end{aligned} φ(n)=i=1n[gcd(i,n)=1]=i=1ndgcd(i,n)μ(d)

注意到 d ∣ gcd ⁡ ( i , n ) d|\gcd(i,n) dgcd(i,n) 可以拆成 d ∣ i   &   d ∣ n d|i~\&~d|n di & dn,带进去会变得很方便:
φ ( n ) = ∑ i = 1 n ∑ d ∣ n μ ( d ) [ d ∣ i ] = ∑ d ∣ n μ ( d ) ∑ i = 1 n [ d ∣ i ] = ∑ d ∣ n μ ( d ) n i \begin{aligned} \varphi(n)&=\sum_{i=1}^n\sum_{d|n}\mu(d)[d|i]\\ &=\sum_{d|n}\mu(d)\sum_{i=1}^n [d|i]\\ &=\sum_{d|n}\mu(d)\frac n i \end{aligned} φ(n)=i=1ndnμ(d)[di]=dnμ(d)i=1n[di]=dnμ(d)in

这样就简单证明完了,但是如何从容斥方面来考虑这个柿子的正确性呢?

回顾上面所说:容斥是个反复加减的过程;函数 f ( S ) f(S) f(S) 中的 S S S 常常用来表示限制的集合。

注意这里有什么限制:假设 n n n 可以分解为 p 1 c 1 p 2 c 2 . . . p k c k p_1^{c_1}p_2^{c_2}...p_k^{c_k} p1c1p2c2...pkck,那么当且仅当 i i i 不是任何一个 p j p_j pj 的倍数时,它才与 n n n 互质。这个可以分解成 k k k 条限制,第 j j j 条为 i i i 需要与 p j p_j pj 互质。

考虑反复加减:看一个比较小的例子,当 n = 6 n=6 n=6 时,考虑没有限制时,先加上所有数,即 1 1 1 ~ 6 6 6,然后由于 6 = 2 1 × 3 1 6=2^1\times 3^1 6=21×31,所以我们需要减去 2 2 2 3 3 3 的倍数,注意到这样的话 6 6 6 的倍数会被减去两次,我们需要加回来,所以再加上 6 6 6 的倍数,答案为 6 − 3 − 2 + 1 = 2 6-3-2+1=2 632+1=2

看到这里,是不是已经有熟悉的感觉了?这和上面那个反复加减的例子本质几乎一致!

然后你再回顾 μ \mu μ 的定义:假如 i i i 可以分解为 k k k 个互不相同的质因子,那么 μ ( k ) = ( − 1 ) k \mu(k)=(-1)^k μ(k)=(1)k,这不就正好表示, i i i 的倍数在容斥过程中应该加上还是减去吗!

而当 i i i 拥有平方因子时, i i i 对容斥是没有贡献的,所以 μ ( i ) \mu(i) μ(i) 等于 0 0 0

是不是一切都顺理成章了起来,当初 μ \mu μ 那个奇怪的定义也显得理所当然。

这就是容斥之美,数学的本质往往是很简单的。

二项式反演

二项式反演

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值