前言
人生中第一道紫题,写一篇题解纪念一下。
BSGS
BSGS(拔山盖世,北上广深 )是什么呢?
它是一种能够在O(n )的时间复杂度内求解类似于ax≡b(modp)的算法。
首先,我们设x=ip−j,其中i,j∈[0,p ]
那么这个式子就变成了aip−j≡b(modp)
两边同时乘上aj,很显然,等式变成了
aip≡baj(modp)
到了这一步,我们就可以先枚举j,每次把bajmodp存入哈希表。
然后再枚举i,在哈希表中查找aip,如果找到了,就说明这个等式成立,x就应该是ip−j,如果枚举完了也没找着,就说说明这个等式不成立。
在这个过程中,我们仅仅枚举了两次,时间复杂度只有区区的O(n )
题目大意
看起来这个题目很复杂,但其实就是一个BSGS的模板。
简化一下题意,题目告诉你gamodp和 gbmodp,让你求gabmodp。
观察一下,我们发现
gabmodp
=(ga)bmodp
=(gamodp)bmodp
=Abmodp
也就是说,只要我们把b求出来,那就万事大吉了。
那么如何求b呢?
观察发现:
B=gbmodP
B≡gb(modP)
gb≡B(modP)
这不就是BSGS的模板吗?
我们可以用BSGS求出b,然后把用b求出Abmodp。
有了这个思路,我们就可以开始写代码了!
注:这题很卡常,不要用cincout,记得开longlong,最后要开O2
AC代码(记得开O2):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <bits/stdc++.h> #define int long long using namespace std; int g,n,p; int qpow(int a,int b){ int res=1; while(b){ if(b&1) res=(a*res)%p; a=(a*a)%p; b>>=1; } return res; } int BSGS(int b){ map<int,int>m; int t=ceil(sqrt(p)); for(int i=1;i<=t;i++) m[b*qpow(g,i)%p]=i; for(int i=1;i<=t;i++){ int k=qpow(g,i*t)%p; if(m[k]) return i*t-m[k]; } return -1; }
signed main(){ scanf("%lld%lld%lld",&g,&p,&n); for(int i=1;i<=n;i++){ int A,B; scanf("%lld%lld",&A,&B); int b=BSGS(B); printf("%lld\n",qpow(A,b)%p); } return 0; }
|