感谢Sunshine_cfbsl的文章:https://blog.csdn.net/sunshine_cfbsl/article/details/52425798
算法核心:
- 引入随机数进行判断,判断的结果有可能会出错,但是当检验次数增加的时候,错误的概率会降低到一个很低的程度
算法思路:
前提:
(1)费马小定理:对于一个质数p,取任意整数a,满足gcd(p,a)=1,则有
ap−1≡1(mod(p))
(2)二次探测定理:对于 0<x<p ,若p是素数,则方程:
x2≡1(mod(p))
的解为:
x1=1 , x2=p−1
具体实现:
思路1:
随机多次选取a( a<p ),若
ap−1≡1(mod(p))
不满足,则p为合数.
这种方法不够精确,误判的可能性还是有点大,故引入第二种思路。
思路2:
将p-1分解为 2t∗u,(u∈{x|x=2∗k+1})
令b[0]= au mod p
令 b[i]=b[i−1]2 ,那么 b[t]=a2t∗u
构造出b[i]后,根据二次检测法进行判断,即
如果 b[i]==1 , 则有 b[i−1]==1 或者 b[i−1]==p−1
如果不满足上述条件,则p为合数
模板:
const int MAXN = 65;
long long n, x[MAXN];
long long multi(long long a, long long b, long long p) {
long long ans = 0;
while(b) {
if(b&1LL) ans = (ans+a)%p;
a = (a+a)%p;
b >>= 1;
}
return ans;
}
long long qpow(long long a, long long b, long long p) {
long long ans = 1;
while(b) {
if(b&1LL) ans = multi(ans, a, p);
a = multi(a, a, p);
b >>= 1;
}
return ans;
}
bool Miller_Rabin(long long n) {
if(n == 2) return true;
int s = 20, i, t = 0;
long long u = n-1;
while(!(u & 1)) {
t++;
u >>= 1;
}
while(s--) {
long long a = rand()%(n-2)+2;
x[0] = qpow(a, u, n);
for(i = 1; i <= t; i++) {
x[i] = multi(x[i-1], x[i-1], n);
if(x[i] == 1 && x[i-1] != 1 && x[i-1] != n-1) return false;
}
if(x[t] != 1) return false;
}
return true;
}
相关题目:https://nanti.jisuanke.com/t/25985
题目大意:
给定一个偶数n,求两个质数a、b使得a+b=n
题解:
打个素数表,枚举素数a,用Miller-Rabin判断n-a是否为素数即可
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 65;
unsigned long long n, x[MAXN];
unsigned long long multi(unsigned long long a, unsigned long long b, unsigned long long p) {
unsigned long long ans = 0;
while(b) {
if(b&1LL) ans = (ans+a)%p;
a = (a+a)%p;
b >>= 1;
}
return ans;
}
unsigned long long qpow(unsigned long long a, unsigned long long b, unsigned long long p) {
unsigned long long ans = 1;
while(b) {
if(b&1LL) ans = multi(ans, a, p);
a = multi(a, a, p);
b >>= 1;
}
return ans;
}
bool Miller_Rabin(unsigned long long n) {
if(n == 2) return true;
int s = 8, i, t = 0;
unsigned long long u = n-1;
while(!(u & 1)) {
t++;
u >>= 1;
}
while(s--) {
unsigned long long a = rand()%(n-2)+2;
x[0] = qpow(a, u, n);
for(i = 1; i <= t; i++) {
x[i] = multi(x[i-1], x[i-1], n);
if(x[i] == 1 && x[i-1] != 1 && x[i-1] != n-1) return false;
}
if(x[t] != 1) return false;
}
return true;
}
bool isprime[1000006];
int prime[1000006];
int cnt=0;
void creat()
{
memset(isprime,1,sizeof isprime);
for(int i=2;i<=100000;i++)
{
if(isprime[i]) prime[cnt++]=i;
else continue;
for(int j=i+i;j<=100000;j+=i)
{
isprime[j]=false;
}
}
}
int main()
{
creat();
int t;
scanf("%d",&t);
while(t--)
{
long long n;
scanf("%lld",&n);
for(int i=0;i<cnt;i++)
{
if(Miller_Rabin(n-prime[i]))
{
printf("%lld %lu\n",prime[i],n-prime[i]);
break;
}
}
}
return 0;
}