Miller-Rabin算法与Pollard's Rho算法总结

Miller-Rabin素数测试


费马小定理:

p p 是素数时,对于a[1,p1],满足

ap11(mod p) a p − 1 ≡ 1 ( m o d   p )

但是其逆命题是假命题,也就是说对于 a[1,p1] a ∈ [ 1 , p − 1 ] ,我们测试所有的 ap1 a p − 1 ,就算全部 =1 = 1 p p 也不一定是素数(可能是伪素数),但出错的概率很小。于是可以选择若干个a来测试,再加上下文中的二次探测,正确率就十分接近100%了。

二次探测:

首先有一个显然的性质: x21(mod p)x1/xp1(mod p) x 2 ≡ 1 ( m o d   p ) ⇔ x ≡ 1 / x ≡ p − 1 ( m o d   p )
我们设 p1=2sr p − 1 = 2 s ⋅ r ,序列 bi=a2ir b i = a 2 i ⋅ r
那么 bs=1 b s = 1 ,而且 b0..s1 b 0.. s − 1 要么全部 =1 = 1 ,要么存在 bk=p1 b k = p − 1 bk+1..s1=1 b k + 1.. s − 1 = 1
满足上述条件才可能是素数。

总结一下,Miller-Rabin测试就是选择若干个用来测试的 a a (一般选择前10个素数即可),进行二次探测,如果全部通过就可以认定其为素数了。

Pollard’s Rho大数质因数分解


假设要质因数分解 n n ,我们使用一个伪随机数f(seed)=(seed2+c)modn。先设两个变量 x=y=seed x = y = s e e d ,让 y=f(y) y = f ( y ) 迭代并检测 gcd(|xy|,n) gcd ( | x − y | , n ) 是否 >1 > 1 ,迭代 k k 次之后把x赋为 y y 并把k 2 2 (倍长迭代),直到gcd>1找到了一个因子,或者 x=y x = y (进入循环)则重新换一个 c c 寻找。
该算法期望在迭代O(p)次找到 n n 的一个因子p,考虑到 n n 的质因子中>n的最多只有一个,所以复杂度大概是 O(n14) O ( n 1 4 ) 的。

板子题:BZOJ3667

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define F(x) (mul(x,x,n)+c)%n
using namespace std;
const ll pri[]={2,3,7,61,10007,24251};
ll mx;
ll rd(ll x)
{
    return (((((((ll)rand()<<15)+rand())<<15)+rand())<<15)+rand())%x;
}
ll gcd(ll x,ll y)
{
    if(!y) return x;
    return gcd(y,x%y);
}
ll mul(ll a,ll b,ll mod)
{
    a=(a>=mod?a%mod:a);
    b=(b>=mod?b%mod:b);
    ll tmp=(a*b-(ll)((long double)a/mod*b+1e-2)*mod);
    return tmp<0?tmp+mod:tmp;
}
ll ksm(ll a,ll b,ll mod)
{
    ll re=1;
    for(a%=mod;b;b>>=1,a=mul(a,a,mod))
        if(b&1) re=mul(re,a,mod);
    return re;  
}
ll check(ll a,ll n,ll r,ll s)
{
    ll t=ksm(a,r,n),u=t;
    while(s--)
    {
        t=mul(t,t,n);
        if(t==1&&u!=1&&u!=n-1) return 0;
        u=t;
    }
    if(t!=1) return 0;
    return 1;
}
ll MR(ll n)
{
    ll r=n-1,s=0;
    while(!(r&1)) r>>=1,s++;
    for(int i=0;i<6;i++)
    {
        if(pri[i]==n) return 1;
        if(!check(pri[i],n,r,s)) return 0;
    }
    return 1;
}
ll rho(ll n)
{
    ll a,b,c,d=1,k=2;
    a=b=rd(n);c=rd(n);
    for(ll i=1;d==1;i++)
    {
        a=F(a);
        d=gcd(a>=b?a-b:b-a,n);
        if(i==k) b=a,k<<=1;
    }
    if(d==n) return rho(n);
    return d;
}
void solve(ll x)
{
    if(x<=1) return ;
    if(MR(x)) {mx=max(mx,x);return ;}
    ll t=rho(x);
    solve(t);solve(x/t);
}
int main()
{
    srand(666623333);
    int ca;
    scanf("%d",&ca);
    while(ca--)
    {
        ll x;
        scanf("%lld",&x);
        mx=0;
        solve(x);
        if(mx==x)puts("Prime");
        else printf("%lld\n",mx);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值