题意
给定三个数 y,z,p ,求:
①.x≡yz mod p
②. 满足 xy≡z mod p 的最小正整数x
③. 满足 yx≡z mod p 的最小正整数x
多组询问
解法
对于①操作,直接套用快速幂即可
对于②操作,移项得到: x=z∗y−1%p ,因为 p 是质数,所以直接求y 的逆元然后算出 x 即可
对于③操作,使用BSGS 算法(拔山盖世算法)求解:
对于方程: xA≡B mod p ,令n=⌈p‾‾√⌉ , A=kn−b ,那么有: xkn−b≡B mod p ,移项得到:xkn≡B∗xb mod p ,通过枚举[0,n] 内的每一个 b ,求出xb∗B ,并用哈希表或者 map 记录下来,然后枚举 [1,n] 内的每一个 k ,找到满足xkn≡B∗xb mod p 的b ,那么 A=kn−b
代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#define Rint register int
#define Lint long long int
using namespace std;
int T,L;
map<Lint,Lint> f;
Lint extgcd(Lint a,Lint b,Lint &x,Lint &y)
{
if( !b ) { x=1,y=0;return a; }
Lint d=extgcd( b,a%b,y,x );
y-=a/b*x;
return d;
}
Lint pow(Lint x,Lint k,Lint p)
{
Lint ret=1;
while( k )
{
if( k&1 ) ret=ret*x%p;
x=x*x%p,k/=2;
}
return ret;
}
void BSGS(int y,int z,int p)
{
f.clear();
Lint L=ceil(sqrt(p)),tmp;
tmp=z%p;f[tmp]=0;
for(Lint i=1;i<=L;i++)
{
tmp=tmp*y%p;
f[tmp]=i;
}
Lint t=pow( y,L,p );tmp=1;
for(Lint i=1;i<=L;i++)
{
tmp=tmp*t%p;
if( f[tmp] )
{
Lint g=i*L-f[tmp];
printf("%lld\n",(g%p+p)%p);
return ;
}
}
printf("Orz, I cannot find x!\n");
}
int main()
{
Lint y,z,p;
scanf("%d%d",&T,&L);
while( T-- )
{
scanf("%lld%lld%lld",&y,&z,&p);y%=p;
if( L==1 ) printf("%lld\n",pow(y,z,p));
if( L==2 )
{
z%=p;
if( y==0 && z!=0 ) printf("Orz, I cannot find x!\n");
else printf("%lld\n",z*pow(y,p-2,p)%p);
}
if( L==3 )
{
if( y%p==0 ) { printf( !z ? "1\n":"Orz, I cannot find x!\n");continue ; }
BSGS( y,z,p );
}
}
return 0;
}