BZOJ 4522: [Cqoi2016]密钥破解

时间:2021-11-27 15:35:01

http://www.lydsy.com/JudgeOnline/problem.php?id=4522

题目:给你RSA密钥的公钥和密文,求私钥和原文,其中\(N=pq\le 2^{62}\),p和q为质数。

RSA加密算法:https://en.wikipedia.org/wiki/RSA_(cryptosystem)

N的范围较小,我们可以用pollard-rho算法在期望O(N^0.25)的时间把N分解出来,用exgcd求逆元之后直接代入。

因为懒,写了一个很短的模板。速度还行,进了第一页。

upd:更新了模板,在另一篇文章里面。

/**************************************************************
Problem: 4522
User: will7101
Language: C++
Result: Accepted
Time:392 ms
Memory:1292 kb
****************************************************************/ #include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int MAXN = 100005;
ll mmul(ll a, ll b, ll m){ll r=0;for(;b;b>>=1,a=a+a>=m?a+a-m:a+a)if(b&1)r=r+a=>m?r+a-m:r+a;return r;}
ll mpow(ll a, ll b, ll m){ll r=1;for(;b;b>>=1,a=mmul(a,a,m))if(b&1)r=mmul(r,a,m);return r;}
ll gcd(ll a, ll b){return a?gcd(b%a,a):b;}
ll exgcd(ll a, ll b, ll &x, ll &y){
if(a==0) return x=0, y=1, b;
ll t=exgcd(b%a, a, y, x);
x-=y*(b/a); return t;
}
ll work(ll n, ll c)
{
ll x, y;
x=y=rand();
while(1){
x=(mmul(x,x,n)+c)%n;
y=(mmul(y,y,n)+c)%n;
y=(mmul(y,y,n)+c)%n;
if(x==y) return 1;
ll p=gcd(x>y?x-y:y-x, n);
if(p>1) return p;
}
}
int main()
{
srand(19260817);
ll e, n, C, p, q, c, r, x, y;
cin>>e>>n>>C;
c=1;
while((p=work(n, c))==1) c++;
q=n/p; r=(p-1)*(q-1);
exgcd(e, r, x, y); x=(x+r)%r;
cout<<x<<' '<<mpow(C,x,n);
return 0;
}