导言
最近在学习OI中的数学,什么线性筛、欧拉函数等等。博主觉得这些知识点太繁杂了,决定整理一下,顺便做个笔记,也帮助大家整理一下知识点。顺便NOIP2018_RP++;ヾ(´∀`o)+。(真的只是浅谈)
1. 素数筛法
关于素数筛法,有很多算法可以求解。至于算法的效率,高级算法的时间复杂度相对于暴力也有了质的飞跃。
1.1 暴力枚举筛(别逗了)
要求解$1 \sim N$所有的质数,可以枚举$1 \sim N$所有数,然后对于每个数$K$我们可以枚举$2 \sim \sqrt{K}$,一一判断是否是$K$的因数。时间复杂度$O(N \sqrt{N})$
1.2 Eratosthenes筛法
摘一段百度百科的话。。
筛法是一种简单检定素数的算法。据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274~194年)发明的,又称埃拉托斯特尼筛法(sieve of Eratosthenes)。
好了,具体怎么实现呢?
由于一个合数总是可以分解成若干个质数的乘积,那么如果把质数(最初只知道2是质数)的倍数都去掉,那么剩下的就是质数了。
例如要查找$100$以内的质数,首先$2$是质数,把$2$的倍数去掉;此时$3$没有被去掉,可认为是质数,所以把$3$的倍数去掉;再到$5$,再到$7$,$7$之后呢,因为$8,9,10$刚才都被去掉了,而$100$以内的任意合数肯定都有一个因子小于$10(\sqrt{100})$,所以,去掉$2,3,5,7$的倍数后剩下的都是质数了。
在做EratosthenesEratosthenes的时候我们还可以考虑一个优化:
对于素数$p$,我们只筛除倍数$x \ge p$的数
为什么呢?如果$x<p$,则$x$中一定有比$p$小的素因子,$p∗x$会在前面的筛选过程中被筛除。
1 |
|
1.3 欧拉筛法(线性筛)
素数筛法中最出名的应该算是线性筛了,它能够在$O(N)$的时间复杂度内筛出$1 \sim N$中所有的素数。
简单来说,线性筛就是筛除素数的倍数,但是要保证每个合数只被它的最小素因子筛除。
举个栗子↓↓↓
素数表 | 筛除的数 | 素数表 | 筛除的数 | ||
---|---|---|---|---|---|
2 | {2} | {4} | 13 | {2,3,5,7,11,13} | {26,39} |
3 | {2,3} | {6,9} | 14 | {2,3,5,7,11,13} | {28} |
4 | {2,3} | {8} | 15 | {2,3,5,7,11,13} | {30,45} |
5 | {2,3,5} | {10,15,25} | 16 | {2,3,5,7,11,13} | {32} |
6 | {2,3,5} | {12} | 17 | {2,3,5,7,11,13,17} | {34} |
7 | {2,3,5,7} | {14,21,35,49} | 18 | {2,3,5,7,11,13,17} | {36} |
8 | {2,3,5,7} | {16} | 19 | {2,3,5,7,11,13,17,19} | {38} |
9 | {2,3,5,7} | {18,27} | 20 | {2,3,5,7,11,13,17,19} | {20} |
10 | {2,3,5,7} | {20} | 21 | {2,3,5,7,11,13,17,19} | {42} |
11 | {2,3,5,7,11} | {22,33} | 22 | {2,3,5,7,11,13,17,19} | {44} |
12 | {2,3,5,7,11} | {24} | … | … | … |
枚举$2 \sim N$中的每一个数$i$:
如果$i$是素数则保存到素数表中;
利用$i$和素数表中的素数$prime[j]$去筛除$i \times prime[j]$,为了确保$i \times prime[j]$只被素数$prime[j]$筛除过这一次,要确保$prime[j]$是$i \times prime[j]$中最小的素因子,即$i$中不能有比$prime[j]$还要小的素因子。
1 | void Euler_sieve(int N) |
2. 最大公因数和最小公倍数
OI中求最大公因数的常用方法就是欧几里得算法(辗转相除法)
给个模版吧,时间复杂度为$O(log(a+b))$
1 | int gcd(int a,int b) {return b==0?a:gcd(b,a%b);} |
利用一些$gcd$的性质我们也可以很容易的证明出欧几里得算法。
这里就不做说明了。
关于最小公倍数,求法也很简单:$lcm(a,b)=a/gcd(a,b)∗b$
这里最好先除再乘,防止爆$long \space long$
3. 快速幂
顾名思义,快速幂就是快速算底数的$N$次幂。其时间复杂度为$O(log_2N)$, 与朴素的$O(N)$相比效率有了极大的提高。
而快速幂的核心思想就是对指数进行二进制分解。举个栗子或许更好理解
例如:由于$11$的二进制是$1011$,所以$11=2^0+2^1+2^3$。所以可以进行转化$a^{11}=a^{2^0+2^1+2^3}$
于是我们转化为求解$a^{11}=a^{2^0} \times a^{2^1} \times a^{2^3}$
效率就可以大大的提升,快速幂可以用位运算来实现
b & 1 //取b二进制的最低位,判断和1是否相同,相同返回1,否则返回0,可用于判断奇偶
b >> 1 //就是将b的二进制右移一位,去掉b的二进制最低位(即第0位),相当于除2
1 | int FastPower(int a,int b) |
4. 欧拉函数
4.1 欧拉函数定义
在数论,对正整数N,欧拉函数是小于或等于N的正整数中与N互质的数的数目$(\varphi(1)=1)$。此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、$\varphi$函数、欧拉商数等。 例如$\varphi(8)=4$,因为$1,3,5,7$均和$8$互质。
4.2 求解欧拉函数
求欧拉函数有一个通式:$\varphi(x)=x∗\prod^{N}_{i=1}(1−\frac{1}{pi})$
其中$p1,p2……pn$为$x$的所有质因数,$x$是不为0的整数。
怎么证明呢,其实有一种很好理解的证明方法。
用数学期望来证明的话,对于$x$的每个素因子$pi$,在$1 \sim N$的范围内,含质因子$pi$的概率为$\frac{1}{pi}$,所以不含质因子$pi$的概率为$1−\frac{1}{pi}$,然后把概率乘起来就是$\varphi(x)$的值了。
4.3 欧拉函数的性质
有一个很明显的定理,当$p$为质数时,$\varphi(p)=p−1$
欧拉定理:对于互质的正整数$a$和$n$,有$a^{\varphi(n)}≡1(mod \space n)$。
欧拉函数是积性函数——若$m,n$互质,$\varphi(mn)=\varphi(m)\varphi(n)$。
若$n$是质数$p$的$k$次幂,$\varphi(n)=p^k−p^{k−1}=(p−1)p^{k−1}$,因为除了$p$的倍数外,其他数都跟$n$互质。
特殊性质:当$n$为奇数时,$\varphi(2n)=\varphi(n)$
欧拉函数还有这样的性质:
设$a$为$N$的质因数
- 若$N\%a=0 \space and \space (N/a)\%a=0$则有$\varphi(N)=\varphi(N/a) \times a$
- 若$N\%a=0 \space and \space (N/a)\%a!=0$则有$\varphi(N)=\varphi(N/a) \times (a−1)$
4.4 线性求欧拉函数
关于欧拉函数的线性筛法,利用上面的两条性质可以实现,下面给出了代码
1 | void Euler_sieve(int N) |