分析:
已知$g^a=A$和$g^b=B$,求$g^{ab}mod P$,可以先求$a$,再得$B^a$。
也即,在$g^aequiv Apmod P$中求$a$。显然$BSGS$。
$g$是原根,这就意味着$g^tmod P;(0leq t<P)$取遍了$[0,P)$,考虑枚举指数找到$a$。
如何加速?考虑一种拆分方法使得可以预处理一部分,即设$t=i imes m-j$,移项,得到$g^{i imes m}equiv A imes g^jpmod P$。
预处理:算出所有$g^{i imes m}$插入到桶里(使用$STL-map$)。使用容器之后要注意常数。
可以发现,当$m=lceilsqrt{P}\, ceil$时有最优复杂度。
实现(100分):

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<map> #include<set> #define IL inline #define RG register #define _1 first #define _2 second using namespace std; typedef long long LL; LL g,p,m; IL LL qpow(LL a,LL b){ LL ret=1; while(b>0){ if(b&1) ret=ret*a%p; a=a*a%p; b>>=1; } return ret; } map<LL,LL>s; IL void init(){ m=sqrt(p)+1; LL t=1,x=qpow(g,m); for(LL i=1;i<=m;i++){ t=t*x%p; s[t]=i*m; } } IL LL calc(LL t){ for(int i=0;i<m;i++){ if(s.find(t)!=s.end()) return s[t]-i; t=t*g%p; } return 0; } int main(){ scanf("%lld%lld",&g,&p); init(); int T; scanf("%d",&T); while(T--){ LL a,b; scanf("%lld%lld",&a,&b); printf("%lld ",qpow(b,calc(a))); } return 0; }
小结:
高级枚举方法get√