破解 D-H 協議
阿新 • • 發佈:2019-02-01
裸的bsgs
我們可以使用分塊來優化暴力列舉,對於Ax≡B(mod C),我們可以令m=⌈⌉,x=i∗m+j,那麼該式子就可以寫成≡B(mod C),於是我們可以將進行預處理,表示達到這個值的指數項為多少,存到一個雜湊表或者map裡,之後我們只要列舉就行了,大致複雜度是O()。(知道了這個,這題就做完了qwq)
不知為何令x=i*m-j就過不了
#include <bits/stdc++.h> using namespace std; #define ll long long ll g,p,n,A,B,m; map<ll,ll>mp; long long int qpow(ll x,ll y) { ll ans=1; while(y) { if(y&1) ans=ans*x%p; x=x*x%p; y>>=1; } return ans; } void intt() { ll x=1; mp[1]=0; for(ll j=1;j<=m;j++) { x=x*g%p; if(!mp[x]) mp[x]=j; } } //巧妙地求逆元 void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y) { if(!b) { d=a,x=1,y=0; } else{ ex_gcd(b,a%b,d,y,x); y-=x*(a/b); } } ll inv(ll x) { ll d,xx,y; ex_gcd(x,p,d,xx,y); return d==1?(xx+p)%p:-1; } ll solve(ll x) { for(ll i=1;i<=m;i++) { ll v=x*inv(qpow(g,i*m))%p; if(mp.count(v)) { return i*m+mp[v]; } } return -1; } int main() { scanf("%lld%lld%lld",&g,&p,&n); m=ceil(sqrt(p)); intt(); while(n--) { scanf("%lld%lld",&A,&B); printf("%lld\n",qpow(B,solve(A))); } return 0; }