素因数分解に

素因数分解に

- > パート1:

算術の基本定理:

一つは有限の質量の積にユニークな番号とすることができるよりも大きい任意の正の整数は、のように書くことができます。

\ [N = \ prod_ {i = 1} ^ m個のP_I ^ {C_I} \]

前記\(C_I \)は正の整数、です\(P_I \)を満たす、素数です\(P_1 <P_2 <... < P_M \を)

- > パート2:

分解:

  • トライアル部門

決定された素数"試行除算"とプライムスクリーニングを"結合\(のエラトステネス\)ふるい"、我々は、スキャンすることができ、\(\ SQRT N \ 2-)各数値\(X∈Z \)であれば、\(Xを\)割り切れるの\(N \)から\(N \)すべての素因数を除去するための\(X \) 累積除去しながら\(X \)数。

上記のアルゴリズムは、この合成数を取り除くために、走査前補因子の特定の数は、このプロセスで割り切れるようにして得られたことを確実にする\(N \)が素数でなければなりません。時間の複雑さがある\(O(\ sqrtのN)\)

注目に値する点場合、すなわち\(N \)は任意ではない\(2- \ SQRT N \)が割り切れる整数であり、\(N \)を分解することなく、素数です。

  • ポラード-Rhoのアルゴリズム

試験区分の時間複雑\(O(\ SQRT N) \) と\(ポラードのRho \)アルゴリズムで実用的複雑性理論\(O(\ SQRTの[4] {N})\)が大きくなっています、プログラムの効率を向上させます。

学習\(ポラードのRho \)アルゴリズムを前に、我々はいくつかの知識を持っている必要があります。

1. ミラー・ラビンアルゴリズム

  • 学習要件:マスターフェルマーの小定理、二次プロービングの定理

したがって、参照、知識の合同を理解するために合同し、関連する中国の剰余定理を

  • フェルマーの小定理:

場合は\(のp \)は素数で、その後、

\ [∀a∈Z、^ Pの\当量の\ PMOD {P} \]

フェルマーの小定理の証明は、「高度なアルゴリズムコンテストへのガイド」を参照してくださいすることができ、読者が自分自身やBaiduのを証明しようとすることができます。

同じ番号の上記定理\(P \) 塩基番号複数の\(\)は、それが上記式を満たす場合、\(P \)は合成数です。

  • 二次プロービング定理:

場合\(P \)は素数であり、
そして\(X ^ 2 \当量。1 \ PMOD {P} \) 次いで\(X \当量1 \ PMOD {P} \) または\(X \当量のp-1 \ PMOD {P} \)

プログラムの精度を向上させるために使用される二次プロービング定理:

数の我々\(P \)を満足します。$ A ^ {P-1 } \当量1 \ PMOD {P} $ [ フェルマーの小定理]

その後のために\(2 | P - 1 \) あなたが得ることができます- \(1 \ PMOD {p型} \ {1 P} {2})^ 2 \当量(X- ^ \ FRAC)は、私たちは少し定理を持っているが、フェルマーのディスカッション$ X ^ \ FRAC {P- 1} {2} MOD {P} \ に基づいて(値(以下\と称する)\ K $)に:

  1. 場合は\(K≠1 \) そしてP≠-K 1 $ \(、その後、\) Pは合成数の$のです\(偽\に戻り\)
  2. もし\(1 K = \。) 次いで再帰\(X ^ \ P-FRAC 1} {2} {\。)
  3. もし\(K-P 1 = \) ない再帰記載の二次プローブ定理によって確認することができない\(P \)を複合であり、\(trueに戻り\ \)

(上記引用文献の一部)

私たちは、数よりも多く取る\(のx \)が精度を向上することができるようになります。

上記を達成するためにミラーラビンのアルゴリズム効率的であり、\((O(logN個)) \) 乱数決定プライムアルゴリズム。

昨日2つのがんのデータやカードを私に長い時間、@の感謝雪のダンスの巨大な男の助けを

そして、2つの素数取る\(61 \)\(24251 \)し、3個の乱数を(\空)\カードが実質的にならないように、。

しかし、私はまだ、次のコードで説明するように、事故のいくつかの種類、ので、3個の乱数をスタックし、着実にACように私は、4個の乱数を書きました。

    //Miller_Rabin 算法
    inline ll qmul(ll x, ll y, ll mod) { //快速乘 
        return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;
    }

    inline ll qpow(ll x, ll m, ll mod) { //快速幂 
        register ll ans = 1;
        while(m) {
            if(m & 1)
                ans = qmul(ans, x, mod) % mod;
            x = qmul(x, x, mod) % mod;
            m >>= 1;
        }
        return ans;
    }

    inline bool FMLT(ll x, ll p) { //费马小定理 
        return qpow(x, p - 1, p) == 1; 
    }

    inline bool Miller_Rabin(ll x, ll p) { 
        if(!FMLT(x, p)) return 0;
        register ll k = p - 1;
        for(;!(k & 1);) {
            k >>= 1;
            ll K = qpow(x, k, p);
            if(K != 1 && K != p - 1) return 0;
            if(K == p - 1) return 1;
        }
        return 1;
    }

    inline bool check(ll p) { // 判断质数 
        if(p == 1) return 0;
        ll t1 = rand(), t2 = rand(), t3 = rand(), t4 = rand();
        if(p == 61 || p == 24251 || p == t1 || p == t2 || p == t3 || p == t4) return 1;
        /*这行写成
        if(p == 2 || p == 3 || p == t1 || p == t2 || p == t3) return 1;     
        (原三个随机数)是可以AC的,但是上面那种写法才是理论正确的,所以多加了一个随机数吧tql
        */
        bool s1 = Miller_Rabin(61, p), s2 = Miller_Rabin(24251, p);
        bool s3 = Miller_Rabin(t1, p), s4 = Miller_Rabin(t2, p);
        bool s5 = Miller_Rabin(t3, p), s6 = Miller_Rabin(t4, p);
        return s1 && s2 & s3 && s4 && s5 && s6;

    }

あなたはこれを超えていると思いますか?あなただけの癌のようなデータの、のように、なぜこの小さな問題を見つけるのだろうか?我々はので\(RANDが\)乱数が現在の数よりも大きくすることができる\(のP- \)の回答に貢献し、あるなし、その後、我々はいくつかの最適化が必要になります。

    ll t1 = rand() % (p - 3) + 2

狭くするランダムワード\([2 ,. 1-P)を\) そして、少しのデータを渡すことができます

しかし、これは我々は4個の乱数が素数の確率に共同決意の数を入れていることを知って、終わりではありません(\ FRAC {1} {4} \)\ので、我々はこの確率を低減する必要がある、あなたは、実験の数を増やす必要があります我々はできる\(チェック\)\(ミラー\ラビン\)一緒に書くと、「数」が追加\(REPEAT \) 一定の時間複雑以内に、我々はいくつかの実験を行いました。

ここでは、最適化の中核である(\(repaetの\)開くように\(23 \)は保険のために、するために開くことができ、もちろん、オーバーしているようだ\(50 \)

    inline bool Miller_Rabin(ll p, int repeat) { 
    
        if(p == 2 || p == 3) return true;
        if(p % 2 == 0 || p == 1) return false;
        //特判
        register ll k = p - 1;
        register int cnt = 0;
        while(!(k & 1)) ++cnt, k >>= 1;
        
        srand((unsigned)time(NULL));//种子
        for(register int i = 0; i < repeat; i++) { 
        
            register ll test = rand() % (p - 3) + 2;
            register ll x = qpow(test, k, p), y = 0;
            
            for(register int j = 0; j < cnt; j++) { //二次探测逆过程
                y = qmul(x, x, p);
                if(y == 1 && x != 1 && x != (p - 1)) 
                    return false;
                x = y;
            }
            if(y != 1) return false; //费马小定理 
        }
        return true;
    }

すべての改善のアイデア@巨大な男のおかげで雪のダンス


2. 高速電力|乗算速い(私はこれは言うまでもないと信じて)

    typedef long long ll;

    ll quick_mul(ll x, ll y, ll mod) {
        return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;  
    }

    ll quick_pow(ll x, ll m, ll mod) {
        ll ans = 1;
        while(m) {
            if(m & 1) 
                ans = ans * x % mod;
            x = x * x % mod;  
            m >>= 1; 
        }
        return ans;
    }

3. \(GCDの\) これは私がそれを言うことはありません)

二つの方法:テクニックを下げ|ユークリッド

以下は、ユークリッドアルゴリズムのコードを示しています。

    ll gcd(ll x,ll y) {
        ll temp;
        while(y) {
            temp = x % y;
            x = y;
            y = temp;   
        }
        return x;
    }

もちろん、これは最も簡単です\(GCDの\)アルゴリズム、我々はまた、最適化されたバイナリになります
参照してください関連除数を

以下は、ポラード-Rhoのアルゴリズムを達成するために:

ここで私は「をご紹介したいと思います誕生日のパラドックス」、この形而上学的なパラドックスの使用は、我々はすぐに品質係数を分解することができます。その後、我々は使用することができます\(RAND()\)無限ループに非準拠の番号を見つけるためになっている時に使用し、ランダム関数を\(フロイド\)リングを判断する方法、「通常の速度」、「2速」 、二つの「初めての出会い」、無限ループ内であること「円を完成」という。

//参考代码 
    void Pollard_Rho(int x) 
    {
        if(test(x)) {//素数测试
            ans=max(x, ans);
            return; 
        }
        ll t1 = rand() % (x-1) + 1;
        ll t2 = (qmul(t2, t2, x)+b) % x;
        ll b = rand() % (x-1) + 1;

        for(;t1 != t2;) {//Flord判断是否进入死循环 
            ll t = gcd(abs(t1-t2), x);
            if(t != 1 && t != x) 
            {
                Pollard_Rho(t),Pollard_Rho(x/t);    
            }
            t1 = (qmul(t1, t1, x)+b) % x;
            t2 = (qmul(t2, t2, x)+b) % x;
            t2 = (qmul(t2, t2, x)+b) % x;//“两倍速” 
        }
    }

コードは、時間複雑度を超える時間複雑さに達していない\(O(\ SQRT [4] N)\) 頻繁に要求メインボトルネック\を(GCDを\)

だからここに形而上学の定数の最適化です\(127 \) 各撮影\(127 \)サンプルが行われました\(1 \)\(GCDの\)は、良い取引のように見えますか?

以下のコードのコア部分を最適化されている(これは本当に私の手を再生することです):

    inline void Pollard_Rho(ll x) {
        if(check(x)) { //检查质数 
            ans = max(x, ans);
            return;
        }
        ll s1 = rand() % (x - 1) + 1;
        ll m = rand() % (x - 1) + 1, p = 1;
        ll s2 = (qmul(s1, s1, x) + m) % x;
        for(register ll i = 1; s1 != s2; i++) { 
        //边界:不进入死循环 即S1 != S2(Floyd判断环) 
            p = qmul(p, abs(s1 - s2), x);
            if(p == 0) {
                ll K = gcd(abs(s1 - s2), x);
                if(K != 1 && K != x) 
                    Pollard_Rho(K), Pollard_Rho(x / K);
                return; 
            }
            if(i % 127 == 0) {
                p = gcd(p, x);
                if(p != 1 && p != x) {
                    Pollard_Rho(p), Pollard_Rho(x / p);
                    return;
                }
                p = 1;
            }
            s1 = (qmul(s1, s1, x) + m) % x;
            s2 = (qmul(s2, s2, x) + m) % x;
            s2 = (qmul(s2, s2, x) + m) % x; //跑两倍 
        }
        //以下部分:最后有可能一个环长不到127 
        p = gcd(p, x);
        if(p != 1 && p != x) {
            Pollard_Rho(p), Pollard_Rho(x / p);
            return;
        }
    }

この点では、テンプレートの質問を完了しようとすることができ、読者の一定の理解があります:

P4718 [テンプレート]ポラード-のRhoアルゴリズムは、最後の章素数篩被験者、下記参照コードを実行することが必要です。

\(ポラード-Rhoの\)アルゴリズム\(コード:\)

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<ctime>

    using namespace std;

    typedef long long ll;
    ll ans,n;

    inline ll qmul(ll x, ll y, ll mod) {  
        return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;
    }

    inline ll qpow(ll x, ll m, ll mod) { 
        register ll ans = 1;
        while(m) {
            if(m & 1)
                ans = qmul(ans, x, mod) % mod;
            x = qmul(x, x, mod) % mod;
            m >>= 1;
        }
        return ans;
    }

    inline bool FMLT(ll x, ll p) { 
        return qpow(x, p - 1, p) == 1; 
    }

    inline bool Miller_Rabin(ll p, int repeat) { 
        if(p == 2 || p == 3) return true;
        if(p % 2 == 0 || p == 1) return false;
        register ll k = p - 1;
        register int cnt = 0;
        while(!(k & 1)) ++cnt, k >>= 1;
        srand((unsigned)time(NULL));
        for(register int i = 0; i < repeat; i++) {
            register ll test = rand() % (p - 3) + 2;
            register ll x = qpow(test, k, p), y = 0;
            for(register int j = 0; j < cnt; j++) {
                y = qmul(x, x, p);
                if(y == 1 && x != 1 && x != (p - 1)) 
                    return false;
                x = y;
            }
            if(y != 1) return false;
        }
        return true;
    }


    inline ll gcd(ll x, ll y) {
        register ll temp;
        while(y) {
            temp = x % y;
            x = y;
            y = temp;
        }
        return x;
    }

    inline void Pollard_Rho(ll x) {
        if(Miller_Rabin(x, 50)) { 
            ans = max(x, ans);
            return;
        }
        register ll s1 = rand() % (x - 1) + 1;
        register ll m = rand() % (x - 1) + 1, p = 1;
        register ll s2 = (qmul(s1, s1, x) + m) % x;
        for(register ll i = 1; s1 != s2; i++) { 
            p = qmul(p, abs(s1 - s2), x);
            if(p == 0) {
                register ll K = gcd(abs(s1 - s2), x);
                if(K != 1 && K != x) 
                    Pollard_Rho(K), Pollard_Rho(x / K);
                return; 
            }
            if(i % 127 == 0) {
                p = gcd(p, x);
                if(p != 1 && p != x) {
                    Pollard_Rho(p), Pollard_Rho(x / p);
                    return;
                }
                p = 1;
            }
            s1 = (qmul(s1, s1, x) + m) % x;
            s2 = (qmul(s2, s2, x) + m) % x;
            s2 = (qmul(s2, s2, x) + m) % x; 
        }
        p = gcd(p, x);
        if(p != 1 && p != x) {
            Pollard_Rho(p), Pollard_Rho(x / p);
            return;
        }
    }

    namespace IN_OUT {
        template <class T>
        inline void read(T &x) {
            static char c;
            static bool op;
            while(!isdigit(c = getchar()) && c != '-');
            x = (op = c == '-')? 0: c-'0';
            while(isdigit(c = getchar()))
                x = x * 10 + c - '0';
            if(op) x = ~x + 1; 
        }

        template <class T>
        inline void output(T x) {
            register char buf[30], *tail = buf;
            if(x == 0) putchar('0');
            else {
                if(x < 0) putchar('-'), x = ~x + 1;
                for(; x; x /= 10) *++tail = x % 10 + '0';
                for(; tail != buf; --tail)
                    putchar(*tail);
            }
            putchar('\n');
        }
    }

    using namespace IN_OUT;

    int main() {
        read(n);
        for(register int i = 1; i <= n; i++) {
            register ll x; 
            read(x);
            if(Miller_Rabin(x, 50))
                printf("Prime\n");

            else {
                ans=0;
                while(ans == 0)
                    Pollard_Rho(x);
                output(ans);
            }
        }
        return 0;
    }

以下は、記録モジュール評価質問、追加の高速伝送速度とリードバンチです\(登録\)、$ $ 50のREPEATの値。

レコードレビュー

章の練習の終わり※


  1. P2441 role属性ツリー

  2. P1069の細胞分裂

  3. P4358 [CQOI2016]キーをクラック

  4. P4718 [テンプレート]ポラード、Rhoのアルゴリズム

\(終わり\)


\(PS:\)

  • 材料の一部は、李Yudong「アルゴリズムコンテストステップアップガイド」から来ています

  • \(ポラード・フォー\)アルゴリズムを参照します:

アルゴリズムにポラードのRho紹介

[クイック]ポラードさんのRho因数分解アルゴリズム

品質係数の急速な分解PollardRho-

話題の少ない素因数分解、追加してください

おすすめ

転載: www.cnblogs.com/Ning-H/p/11567223.html