摘取了以前的笔记并做了一些补充说明
9,素数判定
O(n) + O(1): 线性筛.
又叫欧拉筛。
先考虑一种朴素的想法。
对于每一个数(k), 我们枚举(i),将(ik)标记为合数。
因为每个数都可以分解成若干个素数的积,我们只需枚举每个素数作为(k)即可。
但是复杂度依然很高,我们考虑优化。
对于每个数,仅用它最小的质因数来筛它。
我们用一个数组存储质数,枚举(i)作为它的倍数,并且每次都判断一下如果(i)是素数,则将其加入素数数组。
然后我们从小到大枚举(pri[j])用其筛除(i * pri[j]).
特别的,如果(!(i mod pri[j])) 那么我们筛完就break.
下面我们来证明这个算法的正确性和复杂度。
正确性:
接下来我们证,如果(!(i mod pri[j])),那么对于后面的(i cdot pri[j+k])来说,用(pri[j+k])来筛一定是不优的,也就是这个剪枝肯定不会导致漏筛。
因为(!(i mod pri[j]))所以我们可以设(i = t cdot pri[j])
那么(i cdot pri[j+k] = t cdot pri[j] cdot pri[j+k])
又知(pri[j+k] > pri[j]),也就是说,用(pri[j+k])来筛,不如等到(i = t cdot pri[j+k])的时候用(pri[j])来筛。
所以这个剪枝肯定是合法的。
复杂度:
那么为什么每个数仅被最小的质因数筛除了呢?
接下来我们证,这个剪枝可以导致每个数仅被最小的质因数筛除.
(pm[m])为(m)的质因数个数,对于一个数(m)设(m = prod_{i = 1}^{pm[m]}p_i),其中(p)序列为升序排列,若(m)不是被(p_1)筛除了,我们假设这个数是(p_t)。
我们先考虑(m)质因数大于(2)个的情况:
那么筛掉(m)时我们枚举到的(i = prod_{i = 1}^{pm[m]}(p_i) / p_t = b cdot p_1),(b)为某个不为(1)正整数。
此时,(i)会在枚举到(p_1)的时候停下,也就是筛完(b cdot p_1 cdot p_1)就不筛了,也就不会筛(m = b cdot p_1 cdot p_t)了。与假设矛盾。
再考虑(m)刚好有两个质因数的情况,此时(m = p_1 cdot p_2),那么根据假设,(m)被(p_2)筛掉了。
也就是在(i = p_1)的时候(m)被筛了。
这显然是不合法的,因为此时(p_2)这个质数还没被加入素数数组。
所以(m)只可能在(i = p_2)时被(p_1)筛掉。与假设矛盾。
综上,假设情况是不可能的,(m)必然会被其最小质因数筛除.
又因为在第二个循环中,每循环一次必筛除一个数,而每个数只会被筛走一次,因此第二个循环的总次数为被筛除的素数个数。所以复杂度是(O(n))
代码:
void get()
{
z[1] = 1;
for(R i = 2; i <= n; i ++)
{
if(!z[i]) pri[++ tot] = i;
//printf("%d
", tot);
for(R j = 1; j <= tot && 1LL * i * pri[j] <= n; j ++)
{
z[i * pri[j]] = 1;
if(!(i % pri[j])) break;
}
}
}
O((sqrt{n})): 暴力枚举(sqrt{n})以内的因子
Miller_Rabin算法:(这部分写的好烂,哪天我重学Miller_Rabin再来更新吧)
根据费马小定理有(a^{p - 1} equiv 1 (mod quad p)),要求p是质数.
那么如果对于等式(a^{p - 1} equiv 1 (mod quad p)),枚举多个a,均满足等式,那么可以认为当前的p有很大概率是素数。
但是依然有很大概率不是,,,因此这个时候采取二次探测来减小错误概率。
首先有定理:若(a^2 equiv 1 (mod quad p))且p为质数,那么a = 1 或 p - 1.
证明如下:若等式成立,则(a^{2} - 1 equiv 0 (mod quad p)).
即((a + 1)(a - 1) equiv 0 (mod quad p)).
因此要么(a + 1 = p) ---> (a = p - 1).
或者(a - 1 = 0) ---> (a = 1).
因为这个探测是在满足费马测试的情况下才进行的,因此对于某个已经被枚举过的a,我们已经有(a^{p - 1} equiv 1 (mod quad p)).我们设当前指数(x = p - 1)
当p不为2且为素数时,(p)一定为奇数,即(p - 1)一定为偶数.
因此我们可以把原式看做(a^{frac{x}{2}} cdot a^{frac{x}{2}} equiv 1 (mod quad p)),其中可以设(t = a^{frac{x}{2}})。
那么原式就是(t cdot t equiv 1(mod quad p))
那么因为这个是直接根据原式化过来的,因此我们已经有它同余1了,因此只需要再判断t是否等于1 或 p - 1即可。
如果t = 1 且 x为偶数,那么我们就又得到了一个新的式子(a^{frac{x}{2}} equiv 1 (mod quad p))
此时因为x为偶数,所以我们依然这个把这个新式子当做上面的式子重新做探测,直到不满足t = 1且x为偶数为止。