大数因数分解pollard rho

  1. 快速乘&快速幂
  2. 费马小定理
  3. 二次探测定理
  4. pollor rho
  5. miller rabin

传送门hdu3864

在介绍pollard rho算法之前,先普及一下快速乘法及快速幂,因为大数的乘法之类的可能会爆long long;

#include<cstdio>
#include<iostream>

using namespace std;

long long p,n;

int mul(long b,long a)//快速乘
{
    long long ret=0;
    while(b)
    {
        if(b&1)
        {
            ret=(ret+a)%p;
        }
        b>>=1;
        a=(a+a)%p;
    }
    return ret;
}

int pow(long long a,long long n)//快速幂
{
    long long ret=1;
    while(n)
    {
        if(n&1)
        {
            ret=mul(ret,a);
        }
        n>>=1;
        a=mul(a,a);
    }
    return ret;
}

int main()
{
    while(scanf("%I64d%I64d",&n,&p))
    {
        printf("%I64d",pow(2,n)%p);
    }
}

费马小定理

假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)。
即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的 (p-1)次方除以p的余数恒等于1。

证明

引理1.
  若a,b,c为任意3个整数,m为正整数,且(m,c)=1,则当ac≡bc(modm)时,有a≡b(modm)

证明:ac≡bc(mod m)可得ac–bc≡0(mod m)可得(a-b)c≡0(mod m)因为(m,c)=1即m,c互质,c可以约去,a– b≡0(mod m)可得a≡b(mod m)

引理2.
  设m是一个整数,且m>1,b是一个整数且(m,b)=1.如果a1,a2,a3,a4,…am是模m的一个完全剩余系,则ba[1],ba[2],ba[3],ba[4],…ba[m]也构成模m的一个完全剩余系.

证明:若存在2个整数ba和ba[j]同余即ba≡ba[j](mod m),根据引理1则有a≡a[j](mod m).根据完全剩余系的定义可知这是不可能的,因此不存在2个整数ba和ba[j]同余.所以ba[1],ba[2],ba[3],ba[4],…ba[m]构成模m的一个完全剩余系.

构造素数 p 的完全剩余系
{1,2,3,4……,p-1}
因为 gcd(a,p)==1,由引理2可得
{a,2a,3a,4a,5a……(p-1)a}也为完全剩余系;

则有完全剩余系性质可得1*2*3*4*5…..*(p-1)==a*2a*3a*4a*5a……(p-1)a%p;
所以(p-1)!≡(p-1)!*a^(p-1) (mod p);
a^(p-1)≡1(mod p)

二次探测定理:

如果n是一个素数,且n>x>0,则方程x²%n=1的解为:x=1或 x=n-1.
证明:
除x=1这个解外,剩下的x满足 n>x>√n , n²>x²>n;
那么则有x²=n+1 2n+1 3n+1……(n-2)n+1 …(n-1)n+1
由于n是素数,所以n不可分解,所以只有(n-2)n+1可化为平方形式,即x=n-1;

pollard rho算法带有一定的概率性,但也算是比较靠谱的一种板子了,错判率大概只有4^(-s),s值是自定的;
该算法主要是将大数不断分解为小数;
费马小定理伪质数推断可知,如果n是一个正整数,如果存在和n互素的正整数a满足 a^(n-1)≡ 1(mod n),我们说n是基于a的伪素数。如果一个数是伪素数,那么它几乎肯定是素数,多次查询,则误判几率能降到极低;
所以不断构造随机数x1,找到这样一个因子p,使p=gcd(x1-x2,n);若p==1则构造失败,基于x1不断调整x2,否则p就是a的一个因数,递归继续找p,及n/p;

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<ctime>
using namespace std;
long long factor[1000005];
int tot;
const int S=50;

long long mult(long long a,long long b,long long c)
{
    a%=c;
    b%=c;
    long long ret=0;
    while(b)
    {
        if(b&1)
        {
            ret=(ret+a)%c;
        }
        b>>=1;
        a<<=1;
        if(a>=c)a%=c;
    }
    return ret;
}

long long pow(long long x,long long n,long long mod)
{
    if(n==1)return x%mod;
    x%=mod;
    long long tmp=x;
    long long ret=1;
    while(n)
    {
        if(n&1)
        {
            ret=mult(ret,tmp,mod);
        }
        tmp=mult(tmp,tmp,mod);
        n>>=1;
    }
    return ret;
}

bool check(long long a,long long n,long long x,long long t)
{
    long long ret=pow(a,x,n);
    long long last=ret;
    for(int i=1;i<=t;i++)
    {
        ret=mult(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1)return true;//是合数
        last=ret;
    }
    if(ret!=1)return true;
    return false;
}

bool miller_rabin(long long n)//判素数
{
    if(n<2)return false;
    if(n==2) return true;
    if((n&1)==0)return false;
    long long x=n-1;
    long long t=0;
    while((x&1)==0)
    {
        x>>=1;
        t++;
    }
    for(int i=0;i<S;i++)
    {
        long long a=rand()%(n-1)+1;
        if(check(a,n,x,t))//如果检查出来是合数
        return false;
    }
    return true;
}

long long gcd(long long a,long long 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;
}

long long pollard_rho(long x,long long c)
{
    long long i=1,k=2;
    long long x0=rand()%x;
    long long y=x0;
    while(1)
    {
        i++;
        x0=(mult(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;
        }
    }
}
    void findphi(long long n)
    {
        if(miller_rabin(n))
        {
            factor[tot++]=n;
            return;
        }
        long long p=n;
        while(p>=n)
        {
            p=pollard_rho(p,rand()%(n-1)+1);

        }
        findphi(p);
        findphi(n/p);
    }

    int main()
    {
        long long n;
        while(scanf("%I64d",&n)!=EOF)
        {
            tot=0;
            findphi(n);
            for(int i=0;i<tot;i++)
            printf("%I64d",factor[i]),printf("\n");
            if(miller_rabin(n))printf("yes\n");
            else printf("no\n");
        }
        return 0;
    }
发布了20 篇原创文章 · 获赞 1 · 访问量 6325

猜你喜欢

转载自blog.csdn.net/yichengchangan/article/details/71643615