miller_rabin 소수 판정 + Pollard-rho 소 인수 분해

A는 miller_rabin 소수성
miller_rabin 소수성 테스트는 많은 수의 소수가 있는지 여부를 확인하는 데 사용되는 알고리즘입니다. miller_rabin이 확률 알고리즘이며, 이는 시험의 수가 S, 다음 에러의 확률이 4 ^이다 설정 오류의 특정 확률을 가지고 - (S)
알고리즘의 이론적 근거 :

  1. 페르마 정리 A는 임의의 양의 정수 (1≤ a≤ N-1)이고, n은 다음 홀수 소수하는 ^ (N-1) ≡ 1 개조 N 인 경우.
  2. N이 홀수 소수 인 경우 * R 형체 -3,4- 2와 같이 N-1 발현, R은 홀수, A는이고 n은 임의의 정수 비교적 프라임 후 ^ RN ≡ 1 개조 N 또는 j의 (0 ≤ j≤ S-1 j∈Z)은 ^ (2jr) ≡ -1 개조 N 보유 방정식.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int times = 20;
int number = 0;

map<ll, int>m;
ll Random(ll n)			///生成[0,n]的随机数
{
    return ((double)rand()/RAND_MAX*n+0.5);
}

ll q_mul(ll a,ll b,ll mod) ///快速乘计算 (a*b) % mod
{
    ll ans=0;
    while(b)
    {
        if(b&1)
        {
            b--;
            ans=(ans+a)%mod;
        }
        b/=2;
        a=(a+a)%mod;
    }
    return ans;
}

ll q_pow(ll a,ll b,ll mod) ///快速幂计算 (a^b) % mod
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans=q_mul(ans,a,mod);
        b/=2;
        a=q_mul(a,a,mod);
    }
    return ans;
}

bool witness(ll a,ll n )
///miller_rabin算法的主体
///用检验算子a来检验n是不是素数
{
    ll temp=n-1;
    int j=0;
    while(temp%2==0)
    {
        temp/=2;
        j++;
    }
    ///将n-1拆分为a^r*s
    ll x=q_pow(a,temp,n ); ///得到a^r mod n
    if(x==1||x==n-1)
        return true;	///余数为1则为素数
    while(j--) ///否则试验条件2看是否有满足的 j
    {
        x=q_mul(x,x,n);
        if(x==n-1)
            return true;
    }
    return false;
}

bool miller_rabin(ll n)  
///检验n是否是素数
{
    if(n==2)
        return true;
    if(n<2||n%2==0)
        return false;		    ///如果是2则是素数,如果<2或者是>2的偶数则不是素数
    for(int i=1; i<=times; i++) ///做times次随机检验
    {
        ll a=Random(n-2)+1;     ///得到随机检验算子 a
        if(!witness(a,n))		///用a检验n是否是素数
            return false;
    }
    return true;
}


int main( )
{
    ll tar;
    while(cin>>tar)
    {
        if(miller_rabin(tar))	///检验tar是不是素数
            cout<<"Yes, Prime!"<<endl;
        else
            cout<<"No, not prime."<<endl;
    }
    return 0;
}

둘, 폴라드-RHO 인수 분해
폴라드-RHO 분해 시간 복잡도는 (N ^ 1/4 O )
큰 정수 n에 대해, 우리는 임의의 수의 걸릴 N X 품질 계수의 확률이 작이며 우리는 두 숫자 X1 및 그 차이 (n)의 계수가되도록 X2를 취할 경우, 확률은 X1 및 X2가 GCD되도록 취해진 경우 ((X1-X2)을 크게 할 것 > n)이 1보다 높은 확률. 이 폴라드-의 Rho 알고리즘의 기본 생각이다.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;

ll x[maxn], ans;
queue<ll> aria;

ll multi(ll a, ll b, ll p)	//快速乘
{
    ll ans = 0;
    while(b)
    {
        if(b & 1LL)
            ans = (ans+a)%p;
        a = (a+a)%p;
        b >>= 1;
    }
    return ans;
}

ll qpow(ll a, ll b, ll p)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1LL)
            ans = multi(ans, a, p);
        a = multi(a, a, p);
        b >>= 1;
    }
    return ans;
}

bool miller_rabin(ll n)
{
    if(n == 2)
        return true;
    int s = 20, i, t = 0;
    ll u = n-1;
    while(!(u&1))
    {
        t++;
        u >>= 1;
    }
    while(s--)
    {
        ll a = rand()%(n-2)+2;
        x[0] = qpow(a, u, n);
        for(i = 1; i <= t; i++)
        {
            x[i] = multi(x[i-1], x[i-1], n);
            if(x[i] == 1 && x[i-1] != 1 && x[i-1] != n-1)
                return false;
        }
        if(x[t] != 1)
            return false;
    }
    return true;
}

ll gcd(ll a, ll b)
{
    if(b == 0)
        return a;
    else
        return gcd(b, a%b);
}

ll Pollard_Rho(ll n, int c)
{
    ll i = 1, k = 2, x = rand()%(n-1)+1, y = x;
    while(1)
    {
        i++;
        x = (multi(x, x, n)+c)%n;
        ll p = gcd((y-x+n)%n, n);
        if(p != 1 && p != n)
            return p;
        if(y == x)
            return n;
        if(i == k)
        {
            y = x;
            k <<= 1;
        }
    }
}

void calc(ll n, int c)
{
    if(n == 1)
        return;
    if(miller_rabin(n))
    {
        aria.push(n);
        return;
    }
    ll p = n, k = c;
    while(p >= n)
    {
        p = Pollard_Rho(p, c--);
    }
    calc(p, k);
    calc(n/p, k);
}

int main()
{
    ll n;
    while(~scanf("%lld", &n))
    {
        calc(n, 107);
        cout << aria.front();
        aria.pop();
        while(!aria.empty())
        {
            cout << "*" << aria.front();
            aria.pop();
        }
        cout << endl;
    }
    return 0;
}
게시 된 317 개 원래 기사 · 원 찬양 (105) ·은 20000 +를 볼

추천

출처blog.csdn.net/weixin_43460224/article/details/104443160