这里讲一下普通的 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;
}