题意:给了两个数(n,c),(n=p*q),(p)和(q)是一个未知的数(x)前后的两个质数,(c = f^{2^{30}+3} mod n)。让求(f)的值。
题解:参考大佬博客
我们先来了解一下(RSA解密)
再回头来看这个式子(c = f^{2^{30}+3} mod n),让求(f)是不是就是给了原来的数字,让求密文?
对应着上面的,我们就有设(e = 2^{30}+3),那么(c = f^{e} mod n),(f = c^{d}modn),到这儿我们就发现了,我们不知道(d)是什么;
根据上面(RSA)加密的描述可以知道(left ( d*e ight ) mod left [ left ( p-1 ight )left ( q-1 ight ) ight ]equiv 1)
设(r = left ( p-1 ight )left ( q-1 ight )),就是(left ( d*e ight )mod r equiv 1)
求解方程 (a*xequiv bleft ( mod n ight )x未知) 相当于求解方程 (ax+ny=b,所以这里我们相当于求解方程ex+ry=1),解线性同余方程即可得出(d)。
问题又来了(r)我们不知道是啥......
看上面我们设的(r = left ( p-1 ight )left ( q-1 ight )),那么求(r)的问题变成了求(p,q)的问题,(n=p*q),(n)题目已经给了,我们可以在(sqrtleft ( n ight ))附近找(p,q)
综上所述,我们先求出(p,q),再求出(d),最后求出(f)
AC_Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef long double ld; 5 #define endl ' ' 6 const int inf=0x3f3f3f3f; 7 const int maxn=2e5+10; 8 const ll maxm=1073741827; 9 10 11 ll n,c; 12 13 ll exgcd(ll a,ll b,ll &x,ll &y){ 14 if( b==0 ){ 15 x=1;y=0; 16 return a; 17 } 18 ll d=exgcd(b,a%b,y,x); 19 y-=a/b*x; 20 return d; 21 } 22 23 ll qpow(ll a,ll b,ll mod){ 24 ll res=1; 25 while( b ){ 26 if( b&1 ) res=res*a%mod; 27 a=a*a%mod; 28 b>>=1; 29 } 30 return res; 31 } 32 33 ll mul(ll a,ll b,ll c){ 34 return (a*b-(ll)((ld)a*b/c)*c+c)%c; 35 } 36 37 ll pw(ll x, ll n, ll mod) { 38 ll ret = 1; 39 while(n) { 40 if(n&1) ret = mul(ret,x,mod); 41 x = mul(x,x,mod); 42 n >>= 1; 43 } 44 return ret; 45 } 46 47 int main() 48 { 49 int T,cas=0; scanf("%d",&T); 50 while( T-- ){ 51 scanf("%lld%lld",&n,&c); 52 53 ll p=sqrt(n); 54 while( n%p!=0 ) p--; 55 ll q=n/p; 56 ll r=(p-1)*(q-1); 57 58 ll a,b,x,y; 59 a=(1<<30)+3; 60 b=r; 61 exgcd(a,b,x,y); 62 x = ((x%b)+b)%b; //保证是整数 63 // ll f=qpow(c,x,n); //错,因为c,n都太大了这样直接快速幂的话中间会有溢出 64 ll f=pw(c,x,n); //要用这个O(1)的快速乘 65 printf("Case %d: %lld ",++cas,f); 66 } 67 return 0; 68 }