题面
题意
给出四个数g,p,A,B,其中有a,b满足g^a%p=A,g^b%p=B.求g^(a*b)%p.
做法
首先a,b< p,可以发现只要求出a,b中的任意一个值即可得到答案,但如果暴力枚举a的话复杂度为O(p),显然过不了.
可以考虑分块,令k=sqrt(p),那么就可以得到如下等式:
a=u*p+v(u,v<=k)
所以g^(u *p) *g^v=A
移项得g^(u *p)=A *Inv(g^v)
因此可以预处理出Inv(g^v)(0<= v < k)的值,存到一个map中,然后暴力枚举u就可以求出a,其复杂度为O(sqrt(n)*log(n)).
代码
#include<iostream>
#include<cstdio>
#include<map>
#define ll long long
using namespace std;
ll g,M,A,B,T,sq;
map<ll,ll>mm;
inline ll po(ll u,ll v)
{
ll res=1;
for(;v;)
{
if(v&1) res=res*u%M;
u=u*u%M;
v>>=1;
}
return res;
}
inline void get()
{
ll i;
for(i=0;i*i<=M;i++)
{
mm[po(g,i)]=i;
}
sq=i-1;
}
int main()
{
ll i,j,tmp;
cin>>g>>M>>T;
get();
while(T--)
{
scanf("%lld%lld",&A,&B);
for(i=0;;i++)
{
tmp=A*po(po(g,i*sq),M-2)%M;
if(mm.count(tmp))
{
printf("%lld\n",po(B,i*sq+mm[tmp]));
break;
}
}
}
}