• poj1811


    题意:给定一个64位整数,问是否为质数,如果不是,则输出其最小因子。

    分析:

    经典题!!

    数学题

    miller_rabbin素数判定。若不是,则pollard_rho分解质因子,找到最小即可。

    Miller-rabin

    Miller-rabin算法是一个用来快速判断一个正整数是否为素数的算法。它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1。也就是对于所有小于p的正整数a来说都应该复合a^(p-1) mod p恒等于1。那么根据逆否命题,对于一个p,我们只要举出一个a(a<p)不符合这个恒等式,则可判定p不是素数。Miller-rabin算法就是多次用不同的a来尝试p是否为素数。

    但是每次尝试过程中还做了一个优化操作,以提高用少量的a检测出p不是素数的概率。这个优化叫做二次探测。它是根据一个定理:如果p是一个素数,那么对于x(0<x<p),若x^2 mod p 等于1,则x=1或p-1。逆否命题:如果对于x(0<x<p),若x^2 mod p 不等于1,则p不是素数。根据这个定理,我们要计算a^(p-1) mod p是否等于1时,可以这样计算,设p-1=(2^t) * k。我们从a^k开始,不断将其平方直到得到a^(p-1),一旦发现某次平方后mod p等于1了,那么说明符合了二次探测定理的逆否命题使用条件,立即检查x是否等于1或p-1,如果不是则可直接判定p为合数。

    pollard-rho

    这是一个用来快速对整数进行质因数分解的算法,需要与Miller-rabin共同使用。求n的质因子的基本过程是,先判断n是否为素数,如果不是则按照一个伪随机数生成过程来生成随机数序列,对于每个生成的随机数判断与n是否互质,如果互质则尝试下一个随机数。如果不互质则将其公因子记作p,递归求解p和n/p的因子。如果n是素数则直接返回n为其素因子。

    至于这个随机数序列是如何生成的暂时还不能理解,而且也是有多种不同的方式。这个序列生成过程中会产生循环,遇到循环则立即退出。

    View Code
    #include <cstdio>
    #include
    <cstdlib>
    #include
    <ctime>
    #include
    <cstring>
    #include
    <iostream>
    constint S=20;
    usingnamespace std;

    typedef
    longlong LL;
    #define maxn 10000

    LL factor[maxn];
    int tot;

    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[64],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;
    }

    bool check(LL a,LL n,LL x,LL t){ //以a为基,n-1=x*2^t,检验n是不是合数
    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) return1;
    last
    =ret;
    }
    if (ret!=1) return1;
    return0;
    }

    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) return0;
    return1;
    }

    LL gcd(LL a,LL b){
    if (a==0) return1;
    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));
    int t;
    scanf(
    "%d",&t);
    while (t--){
    LL n;
    scanf(
    "%I64d",&n);
    if (!Miller_Rabin(n)) printf("Prime\n");
    else{
    tot
    =0;
    findfac(n);
    LL ans
    =n;
    for (int i =0; i < tot; i++)
    ans
    = min(ans, factor[i]);
    printf(
    "%lld\n",ans);
    }
    }
    }
  • 相关阅读:
    样式
    样式表的类别、选择器和优先级
    随记
    框架
    表单元素
    HTLM内容容器标签和常用标签
    HTML5的意义、改变以及全局属性
    11月21日html基础
    感想 目标和展望
    C++结构体实例和类实例的初始化
  • 原文地址:https://www.cnblogs.com/rainydays/p/2162049.html
Copyright © 2020-2023  润新知