[CQOI2016]密钥破解

文章目录

  • 一.题目
  • 二.题解
  • 三.Code
  • 谢谢!

难啊!

一.题目

传送门

二.题解

这道题不知道大家有没有看出来,其实是一道数论板题,Pollard rho算法板题。
其实特别难看出来,但只要我们一分析就什么都水落石出了。
分析
N = p ∗ q ① N = p * q\quad① N=pq
r = ( p − 1 ) ∗ ( q − 1 ) ② r = (p - 1) * (q - 1)\quad② r=(p1)(q1)
g c d ( r , e ) = 1 ③ gcd(r,e) = 1\quad③ gcd(r,e)=1
e ∗ d ≡ 1 ( m o d r ) ④ e * d \equiv 1(mod\quad r)\quad④ ed1(modr)
n e ≡ 1 ( m o d N ) ⑤ n^{e}\equiv 1(mod\quad N)\quad⑤ ne1(modN)
c d ≡ n ( m o d N ) ⑥ c^{d}\equiv n(mod\quad N)\quad⑥ cdn(modN)
已知: N , e , c N,e,c N,e,c

  • 这样一分析也就一目了然:
    先用Pollard rho分解出p和q
    然后用扩展欧几里得求出d
    最后再求出n即可
  • 再说一下如何用欧几里得:
    可以看到,④式可以变式为:
    e ∗ d + r ∗ x = 1 ( x 求 出 来 之 后 没 有 用 , 只 是 当 一 个 参 数 ) e*d + r * x = 1 (x求出来之后没有用,只是当一个参数) ed+rx=1(x)

最后上代码:

三.Code

#pragma GCC optimize(2)
#include 
#include 
#include 
#include 
#include 
#include 
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;
}

谢谢!

你可能感兴趣的:(数论)