POJ 1811 Prime Test 【快速判质+因子分解】【模板】

本文介绍了一种高效的素性检测方法——Miller-Rabin算法,并结合Pollard分解法寻找非素数的最小因子。通过具体的C++实现代码展示了如何利用这些算法来判断一个给定整数是否为素数,以及当它不是素数时如何找到其最小的真因子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



题意:

  

       给你一个数,判断是否是素数,是的话输出prime 不是素数输出最小因子。



题解:


      快速判质Miller_Rabin 算法, 根据费马小定理 a^(p-1)%p==1 检测是否符合素数性质,当然有伪素数,不过概率很小,多测几次就行了。


      然后Pollard 分解因子,顺序是无序的,然后找到最小的那个。


  poj  g++ 无法使用 srand()函数,



#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define ll __int64
using namespace std;
const int S=8;
ll ans;
ll gcd(ll a,ll b){
    ll t;
    while(b){
        t=a;a=b;
        b=t%b;
    }
    if(a>=0) return a;
    else return -a;
}
ll mul_mod(ll a,ll b,ll c){
    a%=c;
    b%=c;
    ll ret=0;
    ll tem=a;
    while(b){
        if(b&1){
            ret+=tem;
            if(ret>c) ret-=c;
        }
        tem<<=1;
        if(tem>c) tem-=c;
        b>>=1;
    }
    return ret;
}
ll pow_mod(ll a,ll n,ll mod){
    ll ret=1;
    ll temp=a%mod;
    while(n){
        if(n&1)ret=mul_mod(ret,temp,mod);
        temp=mul_mod(temp,temp,mod);
        n>>=1;
    }
    return ret;
}
bool check(ll a,ll n,ll x,ll t){
    ll ret=pow_mod(a,x,n);
    ll last=ret;
    for(int i=1;i<=t;++i){
        ret=mul_mod(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1) return true;
        last=ret;
    }
    if(ret!=1) return true;
    else return false;
}
bool Miller_Rabin(ll n){
    if(n<2) return false;
    if(n==2) return true;
    if((n&1)==0) return false;
    ll x=n-1;
    ll t=0;
    while((x&1)==0) {x>>=1;t++;}
    //srand(time(NULL));
    for(int i=0;i<S;++i){
        ll a=rand()%(n-1)+1;
        if(check(a,n,x,t))
            return false;
    }
    return true;
}
ll Pollard(ll x, ll c) //对n进行因字分解,找出n的一个因子,注意该因子不一定是最小的
{
    ll i=1,k=2;
    //srand(time(NULL));
    ll x0=rand()%(x-1)+1;
    ll y=x0;
    while (true) {
        i++;
        x0 = (mul_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 solve(ll x,ll c){
    ll ret,m;
    if(x==1) return ;
    if(Miller_Rabin(x)){
        if(x<ans)
            ans=x;
        return ;
    }
    m=x;
    ll k=c;
    while(m>=x)
        m=Pollard(x,k--);
    solve(m,c);
    solve(x/m,c);
}
int main(){
    int T;
    ll p;
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&p);
        ans=p;
        if(Miller_Rabin(p)) puts("Prime");
        else {
            solve(p,107);
            printf("%I64d\n",ans);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值