今天做
dy0607
d
y
0607
的模拟题有一道暴力分可以打
Miller_Rabin
M
i
l
l
e
r
_
R
a
b
i
n
正好之前还没有看懂这个鬼算法,数学一本通上也没讲清
所以下午还是去学了一下 不过中午不睡觉下午效率真低,学了半天才过模板
首先引入两个定理
费马小定理:
如果 a a , 互质, 则有 ap−1=1(mod p) a p − 1 = 1 ( m o d p )
二次探测定理
若 a2=1(mod p) a 2 = 1 ( m o d p ) 如果 p p 为质数 则 或 a=p−1(mod p) a = p − 1 ( m o d p )
定理的证明在此处就不给出了 主要讲下算法流程
Miller_Rabin
1.首先选择几个已知的小质数, 将其倍数筛去
2.选定进行
n
n
次测试,通过次测试不是质数的概率为
(1/4)n
(
1
/
4
)
n
3.首先把要测试的数
x
x
化成(
t
t
为奇数)的形式 再随机一个数满足
0<a<x
0
<
a
<
x
,快速幂计算
tmp=at
t
m
p
=
a
t
, 然后对
tmp
t
m
p
进行
cnt
c
n
t
次二次探测定理进行测试,如果所有测试都通过且最后
tmp=1
t
m
p
=
1
的话就通过了一次测试,这样不断循环直到结束即可,一般来说
n
n
不用选太大, 次就可以了。
Codes
#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
using namespace std;
typedef long long ll;
ll qpow(ll a, ll x, ll mod) {
ll ret = 1;
for(; x; x >>= 1, (a *= a) %= mod)
if(x & 1)
(ret *= a) %= mod;
return ret;
}
bool Miller_Rabin(int mod) {
if(mod == 2 || mod == 7 || mod == 61) return true;
if(mod > 1 && (mod % 2) && (mod % 7) && (mod % 61)) {
For(j, 1, 5) {
int x = mod - 1, tot = 0;
while(x % 2 == 0)
x >>= 1, ++ tot;
int a = rand() % (mod - 1) + 1;
x = qpow(a, x, mod);
For(i, 1, tot) {
int y = 1ll * x * x % mod;
if(y == 1 && x != 1 && x != mod - 1)
return false;
x = y;
}
if(x != 1) return false;
}
return true;
}
return false;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("3383.in", "r", stdin);
freopen("3383.out", "w", stdout);
#endif
int n, q, x;
scanf("%d%d", &n, &q);
For(i, 1, q){
scanf("%d", &x);
if(Miller_Rabin(x))
puts("Yes");
else
puts("No");
}
return 0;
}