2021年ACM竞赛班训练(三)
A题: 验证哥德巴赫猜想
思路:
1、原初哥德巴赫猜想的现代陈述为:任一大于5的整数都可以拆成三个质数之和。通过观察样例输入,不妨假设输入 n n n足够大时: n = a + b + c n = a + b + c n=a+b+c 其中 a , b a, b a,b 在小质数内可实现 ( a , b ∈ ( 2 , 600 ) a,b \in (2, 600) a,b∈(2,600),可利用(埃拉托斯特尼)筛法得到该范围内素数表).
2、对于较大数 c = n − a − b c = n - a - b c=n−a−b 的素性判断考虑Miller-Rabbin算法.
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL pl[601]; //用来装筛法得到的素数pl[i] = 0表示素数,pl[i] = 1表示被筛掉的合数。
//qmul用于计算两数的积,定义该函数目的是防溢出
LL qmul(LL x, LL y, LL mod) {
return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
}
//快速幂算法
LL qpow(LL a, LL n, LL mod) {
LL res = 1, tmp = a;
for(LL i = n; i; i >>= 1){
if(i&1) res = (res*tmp)%mod;
tmp = (tmp*tmp) %mod;
}
return res;
}
//Miller_Rabin算法
LL prime[6] = {2, 3, 5, 233, 331};
bool Miller_Rabin(LL p) {
if(p < 2) return 0;
if(p != 2 && p % 2 == 0) return 0;
LL s = p - 1;
while(! (s & 1)) s >>= 1;
for(int i = 0; i < 5; ++i) {
if(p == prime[i]) return 1;
LL t = s, m = qpow(prime[i], s, p);
while(t != p - 1 && m != 1 && m != p - 1) {
m = qmul(m, m, p);
t <<= 1;
}
if(m != p - 1 && !(t & 1)) return 0;
}
return 1;
}
void solve(LL num) {
//当a, b, c中a, b为小范围内的素数且c(=n-a-b)通过Miller_Rabin检测时即为答案输出
for(int i = 2; i <= 600; i++) {
for(int j = i; j <= 600; j++) {
if(pl[i] == 0 && pl[j] == 0 && Miller_Rabin(num - i - j)) {
printf("%d %d %lld\n", i, j, num - i -j);
return;
}
}
}
}
int main() {
//埃拉托斯特尼筛法实现
for(int i = 2; i <= sqrt(600) + 1; i++) {
if(!pl[i]) for(int j = i*i; j <= 600; j+=i) {
pl[j] = 1;
}
}
//读取数据
LL num;
while(~scanf("%lld", &num)) {
solve(num);
}
return 0;
}
Miller_Rabin算法:
已知:
(1)费马定理:
a
p
−
1
=
1
(
m
o
d
p
)
a^{p-1} = 1 (mod\,p)
ap−1=1(modp)
其中
p
p
p为质数,
a
a
a不是
p
p
p的倍数
(2)二次探测定理:
x
2
≡
1
(
m
o
d
p
)
⇒
x
=
1
o
r
x
=
p
−
1
x^2 \equiv 1 (mod\,p) \Rightarrow x = 1 \,or\, x = p-1
x2≡1(modp)⇒x=1orx=p−1
简要证明:
设
n
n
n是奇素数,则
n
−
1
n-1
n−1必为偶数。令
n
−
1
=
2
q
m
n-1 = 2^qm
n−1=2qm.
对
∀
a
∈
(
1
,
n
)
\forall a \in (1, n)
∀a∈(1,n), 利用费马定理知,
(
a
2
q
m
=
a
n
−
1
)
≡
1
(
m
o
d
n
)
(a^{2^qm} = a ^{n-1}) \equiv 1 (mod\,n)
(a2qm=an−1)≡1(modn)。
由二次探测定理可知:
a
2
q
−
1
m
≡
1
(
m
o
d
n
)
a^{2^{q-1}m} \equiv 1 (mod\,n)
a2q−1m≡1(modn)或
a
2
q
−
1
m
≡
n
−
1
(
m
o
d
n
)
.
a^{2^{q-1}m} \equiv n - 1(mod\,n).
a2q−1m≡n−1(modn).
若
a
2
q
−
1
m
≡
1
(
m
o
d
n
)
a^{2^{q-1}m} \equiv 1 (mod\,n)
a2q−1m≡1(modn)成立,则再次由二次探测定理可知:
a
2
q
−
2
m
≡
1
(
m
o
d
n
)
a^{2^{q-2}m} \equiv 1 (mod\,n)\,
a2q−2m≡1(modn)或
a
2
q
−
2
m
≡
n
−
1
(
m
o
d
n
)
\,a^{2^{q-2}m} \equiv n-1(mod\,n)
a2q−2m≡n−1(modn)
⋯
\cdots
⋯。反复利用刺耳探测定理直到:
a
m
≡
1
(
m
o
d
n
)
a^{m} \equiv 1 (mod\,n)\,
am≡1(modn)或
a
m
≡
n
−
1
(
m
o
d
n
)
a^{m} \equiv n-1 (mod\,n)
am≡n−1(modn)。
综上:如果
n
n
n是素数,则必有
a
m
=
1
(
m
o
d
n
)
a^m = 1\,(mod\,n)
am=1(modn),或存在
a
2
r
m
≡
n
−
1
(
m
o
d
n
)
r
∈
[
0
,
q
−
1
]
a^{2^rm} \equiv n-1(mod\,n)\quad r \in [0, q-1]
a2rm≡n−1(modn)r∈[0,q−1]而使二次检测不能传递到
m
m
m。
算法应用
1、给定(input)奇数
n
n
n, 为判断其素性,先测试
a
2
p
m
≡
1
(
m
o
d
n
)
a^{2^pm} \equiv 1(mod\,n)
a2pm≡1(modn)是否成立。若不成立则
n
n
n必为合数,若成立需要进一步测试。
2、考虑对于Miller序列:
a
m
(
m
o
d
n
)
,
a
2
m
(
m
o
d
n
)
,
a
4
m
(
m
o
d
n
)
,
⋯
,
a
2
q
m
(
m
o
d
n
)
a^m\,(mod\,n), a^{2m}\,(mod\,n),a^{4m}\,(mod\,n), \cdots, a^{2^qm}\,(mod\,n)
am(modn),a2m(modn),a4m(modn),⋯,a2qm(modn),若
a
m
(
m
o
d
n
)
a^m\,(mod\,n)
am(modn) 成立,或存在
a
2
r
m
≡
n
−
1
(
m
o
d
n
)
r
∈
[
0
,
q
−
1
]
a^{2^rm} \equiv n-1(mod\,n)\quad r \in [0, q-1]
a2rm≡n−1(modn)r∈[0,q−1] 则认为n通过Miller_Rabin测试。
注意:1、Miller_Rabin是素数的必要条件,即素数一定可以通过Miller_Rabin测试,不能通过Miller_Rabin的数必为合数。
2、Miller_Rabin不是素数的充分条件,即通过该测试的数可能不是素数。但该算法给出错误结果的概率
p
(
k
)
≤
(
1
4
)
k
p(k) \leq (\frac{1}{4})^k
p(k)≤(41)k其中
k
k
k为测试次数。在实际应用中,效果往往好得多!