BZOJ 2242: [SDOI2011]计算器 BSGS
这里讲一下普通的 BSGS 如何实现:
我们要求解形如 $y^x \equiv z(\mod p)$ 的 $x$ 的整数解(其中 $gcd(y,p)=1$)
我们将 $x$ 写成 $am-b$ 的形式,原式就变为 $y^{am} \equiv z \times y^b (\mod p)$
然后 $b<m$,可以枚举右面所有的取值,然后再枚举左面,整个时间复杂度是 $max(m,\frac{p}{m})$
然后 $m$ 取到 $\sqrt p$ 时时间复杂度是最优的.
这道题中要特判一下无解的情况.
code:
#include <cstdio> #include <map> #include <cstring> #include <cmath> #include <algorithm> #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int mod; map<int,int>bu; int qpow(int x,int y) { int tmp=1; for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod; return tmp; } int exgcd(int a,int b,int &x,int &y) { if(!b) { x=1,y=0; return a;} int gcd=exgcd(b,a%b,x,y),tmp=x; x=y,y=tmp-a/b*y; return gcd; } void work_1() { int i,j,x,y; scanf("%d%d%d",&x,&y,&mod); printf("%d\n",qpow(x,y)); } void work_2() { int i,j,x,y,z,a,b,c; scanf("%d%d%d",&a,&c,&mod),b=mod; int gcd=exgcd(a,b,x,y); if(c%gcd||(a==0&&c!=0)) printf("Orz, I cannot find x!\n"); else { int t=abs(b/gcd); x=(ll)((ll)x*(c/gcd)%t+t)%t; printf("%d\n",x); } } void work_3() { int i,j,y,z,m; scanf("%d%d%d",&y,&z,&mod),m=sqrt(mod)+1; if(y%mod==0&&z) { printf("Orz, I cannot find x!\n"); return; } if(z%mod==1) { printf("0\n"); return ; } bu.clear(); int now=z%mod; bu[now]=0; for(i=1;i<m;++i) now=(ll)now*y%mod,bu[now]=i; int f=qpow(y,m); now=1; for(i=1;i<=m+1;++i) { now=(ll)now*f%mod; if(bu.count(now)) { printf("%d\n",i*m-bu[now]); return; } } printf("Orz, I cannot find x!\n"); } int main() { // setIO("input"); int i,j,T,x; scanf("%d%d",&T,&x); while(T--) { if(x==1) work_1(); if(x==2) work_2(); if(x==3) work_3(); } return 0; }