随机素数测试和大数分解 - poj1811

Prime Test


题意:判断n是不是素数,是的话输出"Prime",否则输出n的最小质因子

数据范围:2 <= N < 2^54

题解:直接上模板 Miller_rabin判定大素数,pollard_rho分解大数


在此奉上邝斌巨巨的模板:     //直接做减法比取模更快,POJ不能用srand(),如果是Runtime Error,去掉这个函数就可以过了。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stdlib.h>
#include<time.h>
#define LL long long

using namespace std;

const int maxn=10000;
LL factor[maxn];
int tot;
const int S=20; //随机算法判定次数,S越大,判错概率越小

//****************************************************************
// Miller_Rabin 算法进行素数测试
//速度快,而且可以判断 <2^63的数
//****************************************************************

LL muti_mod(LL a,LL b,LL c)     //返回(a*b) mod c,a,b,c<2^63
{
    a%=c;
    b%=c;
    LL ret=0;
    while (b)
    {
        if (b&1)
        {
            ret+=a;
            if (ret>=c) ret-=c;
        }
        a<<=1;
        if (a>=c) a-=c;
        b>>=1;
    }
    return ret;
}

LL pow_mod(LL x,LL n,LL mod)   //返回x^n mod c ,非递归版
{
    if (n==1) return x%mod;
    int bit[90],k=0;
    while (n)
    {
        bit[k++]=n&1;
        n>>=1;
    }
    LL ret=1;
    for (k=k-1; k>=0; k--)
    {
        ret=muti_mod(ret,ret,mod);
        if (bit[k]==1) ret=muti_mod(ret,x,mod);
    }
    return ret;
}

//以a为基,n-1=x*2^t,检验n是不是合数,一定是合数返回true,不一定返回false
bool check(LL a,LL n,LL x,LL t)    
{
    LL ret=pow_mod(a,x,n),last=ret;
    for (int i=1; i<=t; i++)
    {
        ret=muti_mod(ret,ret,n);
        if (ret==1 && last!=1 && last!=n-1) return 1;
        last=ret;
    }
    if (ret!=1) return 1;
    return 0;
}

//****************************************************************
// Miller_Rabin()算法素数判定
//是素数返回true.(可能是伪素数,但概率极小)
//合数返回false;
//****************************************************************

bool Miller_Rabin(LL n)
{
    LL x=n-1,t=0;
    while ((x&1)==0) x>>=1,t++;
    bool flag=1;
    if (t>=1 && (x&1)==1)
    {
        for (int k=0; k<S; k++)
        {
            LL a=rand()%(n-1)+1;
            if (check(a,n,x,t))
            {
                flag=1;
                break;
            }
            flag=0;
        }
    }
    if (!flag || n==2) return 0;
    return 1;
}

//************************************************
//pollard_rho 算法进行质因数分解
//************************************************

LL gcd(LL a,LL b)
{
    if (a==0) return 1;
    if (a<0) return gcd(-a,b);
    while (b)
    {
        LL t=a%b;
        a=b;
        b=t;
    }
    return a;
}

LL Pollard_rho(LL x,LL c)
{
    LL i=1,x0=rand()%x,y=x0,k=2;
    while (1)
    {
        i++;
        x0=(muti_mod(x0,x0,x)+c)%x;
        LL d=gcd(y-x0,x);
        if (d!=1 && d!=x)
        {
            return d;
        }
        if (y==x0) return x;
        if (i==k)
        {
            y=x0;
            k+=k;
        }
    }
}

void findfac(LL n)            //递归进行质因数分解N
{
    if (!Miller_Rabin(n))
    {
        factor[tot++] = n;
        return;
    }
    LL p=n;
    while (p>=n) p=Pollard_rho(p,rand() % (n-1) +1);
    findfac(p);
    findfac(n/p);
}

int main()
{
    // srand(time(NULL));//POJ上G++要去掉这句话
    int T;
    scanf("%d",&T);
    long long n;
    while(T--)
    {
        scanf("%I64d",&n);
        if (!Miller_Rabin(n))
        {
            printf("Prime\n");
            continue;
        }
        tot = 0;
        findfac(n);
        long long ans=factor[0];
        for(int i=1; i<tot; i++)
            if(factor[i]<ans)ans=factor[i];
        printf("%I64d\n",ans);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/exchan/article/details/78066320