[CQOI2016]密鑰破解

難啊!

一.題目

傳送門

二.題解

這道題不知道大家有沒有看出來,其實是一道數論板題,Pollard rho算法板題。
其實特別難看出來,但只要我們一分析就什麼都水落石出了。
分析
N=pq N = p * q\quad①
r=(p1)(q1) r = (p - 1) * (q - 1)\quad②
gcd(r,e)=1 gcd(r,e) = 1\quad③
ed1(modr) e * d \equiv 1(mod\quad r)\quad④
ne1(modN) n^{e}\equiv 1(mod\quad N)\quad⑤
cdn(modN) c^{d}\equiv n(mod\quad N)\quad⑥
已知:N,e,c N,e,c

  • 這樣一分析也就一目瞭然:
    先用Pollard rho分解出p和q
    然後用擴展歐幾里得求出d
    最後再求出n即可
  • 再說一下如何用歐幾里得:
    可以看到,④式可以變式爲:
    ed+rx=1(x) e*d + r * x = 1 (x求出來之後沒有用,只是當一個參數)

最後上代碼:

三.Code

#pragma GCC optimize(2)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <ctime>
using namespace std;
#define LL long long

LL p, q, T, e, N, c, d, n, r;

inline LL qkcheng (LL x, LL y, LL mod){
    LL sum = 0;
    x %= mod;
    while (y){
        if (y & 1)
            sum = (sum + x) % mod;
        x = (x << 1) % mod;
        y >>= 1;
    }
    return sum;
}
inline LL qkpow (LL x, LL y, LL mod){
    x %= mod;
    LL sum = 1;
    while (y){
        if (y & 1)
            sum = qkcheng (sum, x, mod);
        x = qkcheng (x, x, mod);
        y >>= 1;
    }
    return sum;
}
inline bool miller_rabin (LL n){
    if (n == 2 || n == 3 || n == 5 || n == 7)
        return 1;
    if (!(n % 2) || !(n % 3) || !(n % 5) || !(n % 7))
        return 0;
    LL m = n - 1, k = 0;
    while (!(m & 1)){
        k ++;
        m >>= 1;
    }
    for (register LL i = 1; i <= 1; i ++){
        LL a = rand () % (n - 1) + 1, x = qkpow (a, m, n), y;
        for (register LL j = 1; j <= k; j ++){
            y = qkcheng (x, x, n);
            if (y == 1 && x != 1 && x != n - 1)
                return 0;
            x = y;
        }
        if (y != 1)
            return 0;
    }
    return 1;
}
inline LL gcd (LL x, LL y){
    if (! y)
        return x;
    return gcd (y, x % y);
}
inline LL pollard_rho (LL n, LL c){
    LL x = rand () % n, y = x, k = 2, i = 1;//全軍出雞,針對rand,你們的含精量呀?
    while (1){
        i ++;
        x = (qkcheng (x, x, n) + c) % n;
        LL d = gcd (fabs (x - y), n);
        if (d > 1 && d < n)
            return d;
        if (x == y)
            return n;
        if (i == k){
            y = x;
            k <<= 1;
        }
    }
}
inline void Find (LL n){
    if (miller_rabin (n)){
        p = n;
        return ;
    }
    LL tmp = n;
    while (tmp >= n)
        tmp = pollard_rho (tmp, rand () % (n - 1) + 1);
    Find (tmp);
    if (p)
        return ;
    Find (n / tmp);
}
inline LL exgcd (LL a, LL b, LL &x, LL &y){
    if (! b){
        x = 1, y = 0;
        return a;
    }
    LL tmp = exgcd (b, a % b, y, x);
    y = ((y - qkcheng(x, a / b, r) % r) % r + r) % r;
    return tmp;
}
int main (){
    srand (20060123);//注意,一定要寫!!!
    scanf ("%lld %lld %lld", &e, &N, &c);
    Find (N);
    q = N / p;
    r = qkcheng ((p - 1), (q - 1), N);
    LL x;
    exgcd (e, r, d, x);
    n = qkpow (c, d, N);
    printf ("%lld %lld\n", d, n);
    return 0;
}

謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章