zoukankan      html  css  js  c++  java
  • POJ1811 Prime Test(Miller-Rabin素数测试算法与Pollard Rho因子分解算法)

    题意:给出一个N(2 <= N < 2^54),如果是素数,输出"Prime",否则输出最小的素因子

    #include <iostream>   //该程序为哥德巴赫猜(想输出所有的组合)
    #include <cmath>
    #include <cstdlib>
    #include <ctime>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    typedef unsigned long long ull;
    typedef unsigned long long LL;
    
    LL n,ans,factor[10001];//质因数分解结果(刚返回时是无序的)
    LL tol;//质因数的个数,数组下标从0开始
    
    LL prime[6] = {2, 3, 5, 233, 331};
    LL qmul(LL x, LL y, LL mod) { // 乘法防止溢出, 如果p * p不爆LL的话可以直接乘; O(1)乘法或者转化成二进制加法
    //快速乘法取模算法
    
        return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
        /*
        LL ret = 0;
        while(y) {
            if(y & 1)
                ret = (ret + x) % mod;
            x = x * 2 % mod;
            y >>= 1;
        }
        return ret;
        */
    }
    
    LL qpow(LL a, LL n, LL mod) {
        LL ret = 1;
        while(n) {
            if(n & 1) ret = qmul(ret, a, mod);
            a = qmul(a, a, mod);
            n >>= 1;//n=n/2二进制乘除法
        }
        return ret;
    }
    
    
    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);
            //二次探测定理卡米歇尔数保证该数为素数
            //卡米歇尔数若一个数为合数当0<x<p,则方程x^p≡a(mod p)
            //二次探测定理如果p是一个素数,0<x<p,则方程x^2≡1(mod p)的解为x=1,p-1
            while(t != p - 1 && m != 1 && m != p - 1) {
                m = qmul(m, m, p);
                t <<= 1;
            }
            if(m != p - 1 && !(t & 1)) return 0;//不是奇数且m!=p-1
        }
        return 1;
    }
    
    LL gcd(LL a,LL b)
    {
        if(a==0)return 1;
        if(a<0) return gcd(-a,b);
        while(b)
        {
            long long t=a%b;
            a=b;
            b=t;
        }
        return a;
    }
    LL Pollard_rho(LL x,LL c)
    {
        LL i=1,k=2;
        LL x0=rand()%x;
        LL y=x0;
        while(1)
        {
            i++;
            x0=(qmul(x0,x0,x)+c)%x;
            long long d=gcd(y-x0,x);
            if(d!=1&&d!=x) return d;
            if(y==x0) return x;
            if(i==k)
            {
                y=x0;
                k+=k;
            }
        }
    }
    //对n进行素因子分解
    void findfac(LL n)
    {
        if(Miller_Rabin(n))//素数
        {
            factor[tol++]=n;
            return;
        }
        LL p=n;
        while(p>=n) p=Pollard_rho(p,rand()%(n-1)+1);
        findfac(p);//递归调用
        findfac(n/p);
    }
    
    
    int main()
    {
        int T;
        long long x;
        ios::sync_with_stdio(false);cin.tie(0);
        cin>>T;
        while(T--)
        {
            cin>>x;
            if(Miller_Rabin(x)) cout<<"Prime"<<endl;
            else
            {
                tol=0;
                findfac(x);
                long long ans=factor[0];
                for(int i=1;i<tol;i++)
                    if(ans>factor[i])
                        ans=factor[i];
                cout<<ans<<endl;
            }
        }
    
    }

    Pollard Rho因子分解算法:https://www.cnblogs.com/dalt/p/8437119.html

  • 相关阅读:
    WEB浏览器与服务器通讯过程
    lua及luci学习
    让apache2不开机启动,管理Ubuntu的开机启动项
    在linux中如何调试C语言程序
    如何去除configure的默认选择-g O2
    C语言使用SQLite3数据库
    Linux下的C程序如何调用系统命令,并获取系统的输出信息到C程序中
    Opencv step by step
    Opencv step by step
    Opencv step by step
  • 原文地址:https://www.cnblogs.com/Fy1999/p/9437684.html
Copyright © 2011-2022 走看看