一、质数
1.定义:若一个正整数无法被除了1和它自身之外的任何自然数整除,则称该数为质数(或素数),否则称该正整数为合数。
在整个自然数集合中,质数的数量不多,分布比较稀疏,对于一个足够大的整数N,不超过N的质数大约有N/lnN个,即每lnN个数中大约有1个质数。
2.质数的判定:试除法
若一个正整数N为合数,则存在一个能整除N的数T,其中2<=T<=sqrt(n)。
证明:
由定义得,因为N是合数,所以存在一个能整除N的数M,其中2<=M<=N-1。
反证法。假设命题不成立,那么这样的数M一定满足sqrt(n)+1<=M<=N-1.
因为M能整除N,所以它们的商N/M也能整除N。而2<=N/M<=sqrt(n),令T=N/M,这与假设矛盾。
故假设不成立,原命题成立。
证毕。
根据上述命题,我们只需要扫描2~sqrt(n)之间的所有整数,依次检查它们能否整除N,若都不能整除,则N是质数,否则N是合数。
复杂度O(sqrt(n))。
1 bool judge(int n){ 2 for(int i=2;i<=sqrt(n);i++){ 3 if(n%i==0) return 0; 4 } 5 return 1; 6 }
其他高效率随机算法:Miller-Robbin
3.质数的筛选
(1)Eratosthenes筛法
Eratosthenes筛法基于这样的想法:任意整数x的倍数2x,3x,…都不是质数。根据质数的定义,上述命题显然成立。
我们可以从2开始,由小到大扫描每个数x,把它的倍数2x,3x,…,[N/x]·x标记为合数。
当扫描到一个数时,若它尚未被标记,则它不能被2~x-1之间的任何数整除,该数就是质数。
1 void Eratosthenes(int n){ 2 memset(v,0,sizeof(v)); 3 for(int i=2;i<=n;i++){ 4 if(v[i]) continue ; 5 cout<<i<<' '; 6 for(int j=1;j<=n/i;j++) v[i*j]=1; 7 } 8 }
实际上,小于x^2的x的倍数在扫描更小的数时就已经被标记过了。
因此,我们可以对Eratosthenes筛法进行优化,对于每个数x,我们只需要从x^2开始,把x^2,(x+1)*x,[N/x]·x标记为合数即可。
Eratosthenes筛法的时间复杂度为O(NloglogN)。
(2)线性筛法
我们在生成一个需要标记的合数时,每次只向现有的数中乘上一个质因子,并且让它是这个合数的最小质因子。
具体地说,我们采用如下的线性筛法,其中v数组记录每个数的最小质因子。每个合数只会被它的最小质因子筛一次,时间复杂度为O(N)。
1 int v[N],prime[N],cnt; 2 void primes(int n){ 3 memset(v,0,sizeof(v)); 4 cnt=0; 5 for(int i=2;i<=n;i++){ 6 if(!v[i]){ 7 v[i]=i,prime[++cnt]=i; 8 } 9 for(int j=1;j<=m;j++){ 10 if(prime[j]>v[i]||prime[j]>n/i) break ; 11 v[i*prime[j]]=prime[j]; 12 } 13 } 14 for(int i=1;i<=cnt;i++){ 15 cout<<prime[i]<<' '; 16 } 17 }
4.质因数分解
(1)算术基本定理
任何一个大于1的正整数都能唯一分解为有限个质数的乘积,可写作:
N=p1^c1*p2^c2…pm^cm
其中ci都是正整数,pi都是质数,且满足p1<p2<…<pm
(2)试除法
结合质数判定的“试除法”和质数筛选的“Eratosthenes筛法”,我们可以扫描2~sqrt(n)的每个数d,若d能整除N,则从N中除掉所有的因子d,同时累计除去的d的个数。
因为一个合数的因子一定在扫描到这个合数之前就从N中被除掉了,所以在上述过程中能整除N的一定是质数。
最终就得到了质因数分解的结果,易知时间复杂度为O(sqrt(n))。
特别地,若N没有被任何2~sqrt(n)的数整除,则N是质数,无需分解。
1 void divide(int n){ 2 cnt=0; 3 for(int i=2;i<=sqrt(n);i++){ 4 if(n%i==0){ 5 prime[++cnt]=i,c[cnt]=0; 6 while(n%i==0) n/=i,c[cnt]++; 7 } 8 } 9 if(n>1){ 10 prime[++cnt]=n,c[cnt]=1; 11 } 12 for(int i=1;i<=cnt;i++){ 13 cout<<prine[cnt]<<'^'<<c[i]<<endl; 14 } 15 }
进阶:“Pollard's Rho”算法
二、约数
1.定义:若整数n除以整数d的余数为0,即d能整除n,则称d是n的约数,n是d的倍数,记为d|n。
2.算术基本定理的推论
在算术基本定理中,若正整数N被唯一分解为N=p1^c1*p2^c2...pm^cm,其中ci都是正整数,pi都是质数,且满足p1<p2p3<p4...<pm,则N的正约数集合可写作:
{p1^b1 p2^b2...pm^bm},其中0<=bi<=ci
N的正约数的个数为:(c1+1)*(c2+1)*(cm+1)
N的所有正约数的和为:(1+p1^1+p1^2+...p1^c1)*...*(1+pm^1+pm^2+...pm^cm)
3.求N的正约数集合:试除法
若d>=sqrt(n)是N的约数,则N/d<=sqrt(n)也是N的约数。约数总是成对出现。
因此,只需要扫描d=1~sqrt(n),尝试d能否整除N,若能整除,则N/d也是N的约数。时间复杂度为O(sqrt(n))
1 int factor[N],cnt; 2 for(int i=1;i*i<=n;i++){ 3 if(n%i==0){ 4 factor[++cnt]=i; 5 if(i!=n/i) factor[++cnt]=n/i; 6 } 7 } 8 for(int i=1;i<=cnt;i++){ 9 cout<<factor[i]<<' '; 10 }
试除法的推论:一个整数N的约数上界为2*sqrt(n)。
4.求1~N每个数的正约数集合:倍数法
若用“试除法”分别求出1~N每个数的正约数集合,时间复杂度过高,为O(N*sqrt(n))。
可以反过来考虑,对于每个数d,1~N中以d为约数的数就是d的倍数d,2d,3d,….[N/d]*d。
以下程序采用“倍数法”求出1~N每个数的正约数集合;
1 vector<int>factor[N]; 2 for(int i=1;i<=n;i++){ 3 for(int j=1;j<=n/i;j++){ 4 factor[i*j].push_back(i); 5 } 6 } 7 for(int i=1;i<=n;i++){ 8 for(int j=0;j<factor[i].size();j++){ 9 cout<<factor[i][j]<<' '; 10 } 11 puts(""); 12 }
上述算法的时间复杂度为O(N+N/2+N/3+…+N/N)=O(NlogN)。
倍数法的推论:1~N每个数的约数个数的总和大约为NlogN。
5.最大公约数
gcd(a,b)=gcd(b,a)
gcd(a,b)=gcd(-a,b)
gcd(a,b)=gcd(|a|,|b|)
gcd(a,0)=|a|
gcd(a,k*a)=|a|
gcd(a*n,b*n)=n*gcd(a,b)
若d|a且d|b,则d|gcd(a,b)
若n|ab且gcd(a,n)=1,则n|b
若gcd(a,p)=1且gcd(b,p)=1,则gcd(a*b,p)=1
(1)定义:
若自然数d同时是自然数a和b的约数,则称d是a和b的公约数。在所有a和b的公约数中最大的一个,称为a和b的最大公约数,记为gcd(a,b)。
若自然数m同时是自然数a和b的倍数,则称m是a和b的公倍数。在所有a和b的公倍数中最小的一个,称为a和b的最小公倍数,记为lcm(a,b)。
同理,我们也可以定义三个数以及更多个数的最大公约数、最小公倍数。
(2)定理:任意a,b属于N+,gcd(a,b)*lcm(a,b)=a*b。
证明:
设d=gcd(a,b),a0=a/d,b0=b/d。根据最大公约数的定义,有gcd(a0,b0)=1。
再根据最小公倍数的定义,有lcm(a0,b0)=a0*b0,于是lcm(a,b)=lcm(a0*d,b0*d)=lcm(a0,b0)*d=a0*b0*d=a*b/d。
证毕。
(3)九章算术-更相减损术:
任意a,b属于N+,a>=b,有gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)。
任意a,b属于N+,有gcd(2a,2b)=2gcd(a,b)。
证明:根据最大公约数的定义,后者显然成立,我们主要证明前者。
对于a,b的任意公约数d,因为d|a,d|b,所以d|(a-b)。因此d也是b,a-b的公约数,反之亦成立。
故a,b的公约数集合与b,a-b的公约数集合相同。于是它们的最大公约数自然也相等,对于a,a-b同理。
证毕。
(4)欧几里得算法:
证明:
若a<b,则gcd(b,a mod b)=gcd(b,a)=gcd(a,b),命题成立。
若a>b,不妨设a=q*b+r,其中0<=r<b。显然r=a mod b。
对于a,b的任意公约数d,因为d|a,d|q*b,故d|(a-q*b),即d|r,因此d也是b,r的公约数。反之亦成立。
故a,b的公约数集合与b,a modb的公约数集合相同。于是它们的最大公约数自然也相等。
证毕。
1 int gcd(int a,int b){ 2 return b?gcd(b,a%b):a; 3 }
使用欧几里得算法求最大公约数的复杂度为0(log(a+b))。
(5)类欧几里得算法:
6.互质与欧拉函数
(1)定义:
任意a,b属于N+,若gcd(a,b)=1,则称a,b互质。
对于三个数或更多个数的情况,我们把gcd(a,b,c)=1的情况称为a,b,c互质;
把gcd(a,b)=gcd(a,c)=gcd(b,c)=1称为a,b,c两两互质。后者显然是一个更强的条件。
(2)欧拉函数:1~N中与N互质的数的个数被称为欧拉函数,记为φ(N)。
若在算术基本定理中,N=p1^c1*p2^c2...pm^cm,则:
φ(N)=N*(p1-1)/p1*(p2-1)/p2*...*(pm-1)/pm=N*Π(1-1/p)
证明:
设p是N的质因子,1~N中p的倍数有p,2p,3p…,(N/p)*p,共N/p个。
同理,若q也是N的质因子,则1~N中q的倍数有N/q个。如果我们把这N/p+N/q个数去掉,那么p*q的倍数被排除了两次,需要加回来一次。
因此,1~N中不与N含有共同质因子p或q的数的个数为:
N-N/p-N/q+N/(p*q)=N*(1-1/p-1/q+1/(p*q))=N*(1-1/p)*(1-1/q)
类似地,可以在N的全部质因子上使用容斥原理,即可得到1~N中不与N含有任何共同质因子的数的个数,也就是与N互质的数的个数。
证毕。
根据欧拉函数的计算式,我们只需要分解质因数,即可顺便求出欧拉函数。
1 int phi(int n){ 2 int ans=n; 3 for(int i=1;i<=sqrt(n);i++){ 4 if(n%i==0){ 5 ans=ans/i*(i-1); 6 while(n%i==0) n/=i; 7 } 8 } 9 if(n>1) ans=ans/n*(n-1); 10 return ans; 11 }
(3)性质:
a.任意N>1,1~N中与N互质的数的和为N*φ(N)/2
b.若a,b互质,则φ(a*b)=φ(a)*φ(b)
证明:
因为gcd(n,x)=gcd(n,n-x),所以与n不互质的数x,n-x成对出现,平均值为n/2。因此,与n互质的数的平均值也是n/2,进而得到性质1。
根据欧拉函数的计算式,对a,b分解质因数,直接可得性质2。把性质2推广到一般的函数上,可以得到“积性函数”的概念。
证毕。
积性函数:如果当a,b互质时,有f(ab)=f(a)*f(b),那么称函数f为积性函数。
c.若f为积性函数,且在算术基本定理中N=Πpi^ci,则f(N)=Πf(pi^ci)
d. 若 p|n且p^2|n,则φ(n)=φ(n/p)*p
e.若p|n但p^2|n==false,则φ(n)=φ(n/p)*(p-1)
f.Σd|n φ(d)=n
证明:
把n分解质因数,按照积性函数的定义,性质3显然成立。
若p|n且p^2|n,则n,n/p包含相同的质因子,只是p的指数不同。直接把φ(n)与φ(n/p)按照欧拉函数的计算公式写出,二者相除,商为p,所以性质4成立。
若p|n但p^2|n==false,则n,n/p互质,由φ是积性函数得φ(n)=φ(n/p)*φ(p),而φ(p)=p-1,所以性质5成立。
设f(n)=Σd|n φ(d)。用乘法分配律展开比较,再利用φ是积性函数,得到:若nm互质,则f(nm)=Σd|nmφ(d)=(Σd|nφ(d))*(Σd|mφ(d))=f(n)*f(m).即Σd|nφ(d)是积性函数。对于单个质因子,f(p^m)=Σd|p^mφ(d)=φ(1)+φ(p)+φ(p^2)+…+φ(p^m)是一个等比数列求和再加1,结果为p^m。所以f(n)=Π(i=1 to m)f(pi^ci)=Π(i=1 to m)pi^ci=n,性质6成立。
证毕。
三、同余
1.定义:若整数a和整数b除以正整数m的余数相等,则称a,b模m同余,记为a同余于b(mod m)。
2.同余类与剩余系:
模m的同余类共有m-1个,它们构成m的完全剩余系。
1~m中与m互质的数代表的同余类共有φ(m)个,它们构成m的简化剩余系。
简化剩余系关于模m乘法封闭,这是因为若a,b(1<=a,b<=m)与m互质,则a*b也不可能与m有相同的质因子,即a*b也与m互质。
再由余数的定义即可得到a*b mod m 也与m互质,即a*b mod m也属于m的简化剩余系
3.费马小定理:若p是质数,则对于任意整数a,a^p=a (mod p)
4.欧拉定理:
5.欧拉定理的推论:
6.扩展欧几里得算法:
Bezout定理:对于任意整数a,b,存在一对整数x,y,满足ax+by=gcd(a,b)
证明:
(1)Bezout定理:
(2)扩展欧几里得算法:
(3)乘法逆元:
7.线性同余方程:
(1)中国剩余定理:
8.高次同余方程:
(1)baby step giant step算法:
9.威尔逊定理:
10.离散对数:
11.阶与原根:
12.二次剩余:
四、矩阵乘法:
五、高斯消元与线性空间:
1.高斯消元:
2.异或高斯消元:
3.线性基:
4.线性空间:
5.行列式:
6.逆矩阵:
7.线性变换:
8.矩阵对角化:
9.分块矩阵乘法:
(1)matrix-tree定理:
六、组合计数
1.加法原理:
2.乘法原理:
3.排列数:
(1)多重集的排列数:
4.组合数:
(1)性质:
(2)组合数求法:
(3)二项式定理:
(4)多重集的组合数:
5.Lucas定理:
6.Catalan数列:
(1)证明:
(2)推论:
七、容斥原理与mobius函数
1.容斥原理:
2.多重集的组合数:
(1)证明:
3.mobius函数:
八、概率与数学期望
1.性质:
九、0/1分数规划:
十、博弈论之SG函数:
1.NIM博弈:
2.公平组合游戏IGG:
3.有向图游戏:
4.Mex运算:
5.SG函数:
6.有向图游戏的和:
(1)定理: