miller——rabin判断素数

我们首先看这样一个很简单的问题:判定正整数\(n\)是正整数

最简单的做法就是枚举\(1\)到\(n\)的所有数看是否有数是\(n\)的因数,时间复杂度\(O(n)\)

稍微优化一下发现只要枚举\(2\)到\(\sqrt{n}\)中的数就可以了

然后发现数据范围\(n\leq 10^{18}\),期望执行次数直接就死掉了QAQ

我们就要考虑新的方法了

首先引入两个定理

1、费马小定理

如果\(p\)是素数,且\(gcd(a,b)=1\),那么\(a^{p-1}\equiv 1(mod \ n)\)

证明什么的你随便找本数论书自己翻一下

注意它的逆定理不一定成立

2、二次探测定理(其实这也没有一个准确的名字)

如果\(p\)是奇素数,\(x<p\),且\(x^2\equiv1(mod\ p)\),那么\(x=1\)或\(xp=-1\)

证明:由同余式知\(x^2-1\equiv0(mod\ p)\),即\(p|(x+1)(x-1)\)

? 又由\(p\)是素数知\(p|x-1\)或\(p|x+1\),解得\(x=1\)或\(x=p-1\)

诶等等zzr没事给证明干嘛?zzr不是最讨厌证明了吗

由上面很简单的证明过程我们可以发现,\(x=1\)和\(x=p-1\)这两个解其实是对所有的\(p\)都成立的

即无论\(p\)取什么值\(x\)取上面两个值是一定可以的

但是当\(p\)是一个合数的时候,此时原同余方程的解\(x\)就不只上面这两个了,而是会有多个

换一句话说:如果上面的\(x\)取到了1和\(p-1\)以外的数,就说明\(p\)不是一个素数了

我们主要利用上面两个性质来进行素数判定

1、取\(2^q*m=n-1\)(\(q,m\)均为正整数且\(m\)为奇数),同时任意取小于\(n\)的正整数\(a\)

2、求出\(a^{n-1}\text%n\),如果这个值不为1那么\(n\)一定是合数(利用费马小定理)

3、遍历\(i\),使得\(1\leq i \leq q\),如果\(2^i*m\text%n=1\)并且\(a^{i-1}*m\text%n!=1或n-1\),那么由二次探测定理就知道原同余方程出现一个特殊解,说明\(n\)不是一个素数

上面的方法有一个小问题:由于费马小定理的逆定理不一定成立(在大多数情况下成立),因此有时我们会对\(n\)进行误判,具体的,每做一次发生误判的概率是\(\frac{1}{4}\)

解决的方法在上面的解法中也有体现:换用不同的\(a\),多进行几次即可

好了上面就是完整的miller-rabin测试了

一道例题:poj3518Prime Gap

题意:两个相邻的素数的差值叫做Prime Gap。输入一个K,求K两端的素数之差,如果K本身是一个素数,输出0;

分析:其实数据很小你直接筛一下也可以

? 或者你直接暴力寻找当前这个数相邻的数是否是质数,两端分别记录第一次找到的质数即可

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
#define int long long
int n;

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<‘0‘) || (ch>‘9‘)) {if (ch==‘-‘) f=-1;ch=getchar();}
    while ((ch>=‘0‘) && (ch<=‘9‘)) {x=x*10+(ch-‘0‘);ch=getchar();}
    return x*f;
}

int mul(int x,int y,int n)
{
    x%=n;y%=n;
    int ans=0,sum=x;
    while (y)
    {
        int tmp=y%2;y/=2;
        if (tmp) ans=(ans+sum)%n;
        sum=(sum+sum)%n;
    }
    return ans;
}

int qpow(int x,int y,int n)
{
    int ans=1,sum=x;
    while (y)
    {
        int tmp=y%2;y/=2;
        if (tmp) ans=mul(ans,sum,n);
        sum=mul(sum,sum,n);
    }
    return ans;
}

bool prime(int m,int q,int a,int n)
{
    int now=qpow(a,m,n);
    if ((now==1) || (now==n-1)) return 1;
    int i;
    for (i=1;i<=q;i++)
    {
        int x=mul(now,now,n);
        if ((x==1) && (now!=1) && (now!=n-1)) return 0;
        now=x;
    }
    if (now!=1) return 0;//其实这里是将费马小定理的检测放在了最后,省去再做一次快速幂
    return 1;
}

bool miller_rabin(int x)
{
    if (x==2) return 1;
    if ((x<2) || (x%2==0)) return 0;
    int num=x-1,tim=0;
    while ((num) && (num%2==0)) {num/=2;tim++;}
    //cout << num << " " <<tim << endl;
    int i;
    for (i=1;i<=10;i++)//一般都会进行20次左右,不过数据范围小对吧2333
    {
        int a=rand()%(x-1)+1;
        if (!prime(num,tim,a,x)) return 0;
    }
    return 1;
}

void work()
{
    if (miller_rabin(n)) {printf("0\n");return;}
    //cout <<1;
    int l=n-1,r=n+1;
    while (!miller_rabin(l)) l--;
    while (!miller_rabin(r)) r++;
    printf("%d\n",r-l);
}

signed main()
{
    n=read();
    while (n)
    {
        work();
        n=read();
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zhou2003/p/9976285.html

时间: 2024-10-07 18:58:17

miller——rabin判断素数的相关文章

POJ1811_Prime Test【Miller Rabin素数测试】【Pollar Rho整数分解】

Prime Test Time Limit: 6000MS Memory Limit: 65536K Total Submissions: 29193 Accepted: 7392 Case Time Limit: 4000MS Description Given a big integer number, you are required to find out whether it's a prime number. Input The first line contains the num

HDU1164_Eddy&#39;s research I【Miller Rabin素数测试】【Pollar Rho整数分解】

Eddy's research I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6664    Accepted Submission(s): 3997 Problem Description Eddy's interest is very extensive, recently he is interested in prime

51nod 1106 质数检测(miller rabin 素数测试.)

1106 质数检测 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出N个正整数,检测每个数是否为质数.如果是,输出"Yes",否则输出"No". Input 第1行:一个数N,表示正整数的数量.(1 <= N <= 1000) 第2 - N + 1行:每行1个数(2 <= S[i] <= 10^9) Output 输出共N行,每行为 Yes 或 No. Input示例 5 2 3 4 5 6

HDU 3864 D_num Miller Rabin 质数判断+Pollard Rho大整数分解

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3864 题意:给出一个数N(1<=N<10^18),如果N只有四个约数,就输出除1外的三个约数. 思路:大数的质因数分解只能用随机算法Miller Rabin和Pollard_rho,在测试多的情况下正确率是由保证的. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <c

POJ2429_GCD &amp;amp; LCM Inverse【Miller Rabin素数測试】【Pollar Rho整数分解】

GCD & LCM Inverse Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9756Accepted: 1819 Description Given two positive integers a and b, we can easily calculate the greatest common divisor (GCD) and the least common multiple (LCM) of a and b.

HDU1164_Eddy&amp;#39;s research I【Miller Rabin素数测试】【Pollar Rho整数分解】

Eddy's research I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6664    Accepted Submission(s): 3997 Problem Description Eddy's interest is very extensive, recently he is interested in prime

POJ2429_GCD &amp; LCM Inverse【Miller Rabin素数测试】【Pollar Rho整数分解】

GCD & LCM Inverse Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9756Accepted: 1819 Description Given two positive integers a and b, we can easily calculate the greatest common divisor (GCD) and the least common multiple (LCM) of a and b.

POJ1811_Prime Test【Miller Rabin素数測试】【Pollar Rho整数分解】

Prime Test Time Limit: 6000MS Memory Limit: 65536K Total Submissions: 29193 Accepted: 7392 Case Time Limit: 4000MS Description Given a big integer number, you are required to find out whether it's a prime number. Input The first line contains the num

如何判断素数

在OI与密码学等各个方面,我们经常会遇到需要判断素数的情况.这个问题看似简单,实则不然.判素就像是排序,只会快排是不能走遍天下的,想要成为一名神犇,就需要接触更多的算法. 一:什么是素数 素数,也可以叫做质数.如果一个大于1的自然数,除去1和他本身,不能被其他数字整除,那么他就是一个素数.任何一个大于1的自然数,要么是素数,要么是可以写做一堆素数相乘. 二:素数的性质 (1)质数p的约数只有两个:1和p. (2)初等数学基本定理:任一大于1的自然数,要么本身是质数,要么可以分解为几个质数之积,且