我是一个玄学研究者
前置玄学芝士
Miller_Rabin
这个玄学算法又有4个前置玄学芝士
rand
费马小定理
是一个欧拉定理( a φ ( x ) ≡ 1 ( m o d x ) a^{\varphi(x)}\equiv1\pmod x aφ(x)≡1(modx))的引理。
就是 p ∈ P ⇒ a p − 1 ≡ 1 ( m o d p ) p\in\mathbb{P}\Rightarrow a^{p-1}\equiv1\pmod p p∈P⇒ap−1≡1(modp)
一般来说,会自然而然地想到:会不会 p ∈ P ⇐ a p − 1 ≡ 1 ( m o d p ) p\in\mathbb{P}\Leftarrow a^{p-1}\equiv1\pmod p p∈P⇐ap−1≡1(modp)呢?
一般来说,是的。但是,有一些数是不符合的,这一类数叫做卡迈克尔数。
但是如果经过多次这种测试的数,是素数的几率就会增加很多……
二次探测定理
懒得写就放图片吧
费马小定理和二次探测定理给出了一个数是素数的必要条件。
如果找到了一个小于 n n n的数 a a a, a a a关于 n n n不满足费马小定理或者二次探测定理,那么 n n n一定是合数。
然后再结合我们神奇的随机数,随机进行几轮测试,就可以愉快的通过了~~
(大喘气)吗??
当然不是。我们需要用一种神奇的技巧。想一想,如果原数是在 l o n g l o n g long\ long long long范围内,那原数在快速幂时自乘就直接爆掉,所以还需要——
快速乘
哪来的快速了,还不如我一个运算符
这里仅给出 O ( log n ) O(\log n) O(logn)的快速乘,想要了解更牛逼的 O ( 1 ) O(1) O(1)快速乘的朋友可以百度一下。
其实和快速幂一个道理,就是把累乘改成累加。
如下:
typedef long long LL;
inline LL mul(LL a, LL b, LL mod) {
//a * b % mod
LL ans = 0;
while(b) {
if(b & 1) ans = (ans + a) % mod;
a = (a << 1) % mod;
b >>= 1;
}
}
于是,我们可以直接运用随缘数来进行测试,一般5轮足矣。
参考代码:节省一下篇幅
gcd
这是基于一个定理的—— ( a , b ) = ( r , b ) (a,b)=(r,b) (a,b)=(r,b),其中 a ≡ r ( m o d b ) a\equiv r\pmod{b} a≡r(modb)
证明:
设 a = m c , b = n c , ( m , n ) = 1 , a = k b + r a=mc,b=nc,(m,n)=1,a=kb+r a=mc,b=nc,(m,n)=1,a=kb+r,则 a = m c = k b + r = k n c + r ⇒ r = ( m − k n ) c a=mc=kb+r=knc+r\Rightarrow r=(m-kn)c a=mc=kb+r=knc+r