传送门
题目描述有问题! y,z,p 中只有 p 为质数!
题目描述有问题! y,z,p 中只有 p 为质数!
题目描述有问题! y,z,p 中只有 p 为质数!
重要的事情说三遍!
对于操作1:
快速幂而已,不存在无解的情况。
对于操作2:
扩展欧几里得算法。有解的条件为: gcd(y,p)|z
证明:
已知
我们知道当 (y,p)=1 时我们可以利用扩展欧几里得求出 xy−ap=gcd(y,p) 即 xy−ap=1 的解 x,a
所以将原式转换一下:
有人有问题吗?
能用扩展欧几里得求这个式子 xzy+azp=1 的解条件不是y,p互质吗?那要不要判断一下呢?
其实是不用的,因为如果满足这个式子 gcd(y,p)|z 的话,我们可以让等式两边同时/gcd(y,p),也就是y,z,p同时/gcd(y,p)。这样的话就保证了y,p一定互质啦。
对于操作3:
只是BSGS算法的模板啦,可以参考本博客BSGS算法学习笔记。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
int T,K,Y,Z,P;
LL ans,m,Y_m,mul,now,x,y,d;
map <LL,LL> hash;
bool pd;
inline LL fast_pow(LL a,LL p){
LL ans=1;
for (;p;p>>=1,a=a*a%P)
if (p&1)
ans=ans*a%P;
return ans;
}
inline LL gcd(LL a,LL b){
if (!b) return a;
else return gcd(b,a%b);
}
inline void exgcd(LL a,LL b,LL &x,LL &y,LL &d){
if (!b) x=1,y=0,d=a;
else exgcd(b,a%b,y,x,d),y-=a/b*x;
}
int main(){
scanf("%d%d",&T,&K);
while (T--){
scanf("%d%d%d",&Y,&Z,&P);
switch (K){
case 1:{
ans=fast_pow(Y,Z);
printf("%lld\n",ans);
break;
}
case 2:{
LL GCD=gcd(Y,P);
if (Z%GCD){
printf("Orz, I cannot find x!\n");
continue;
}
Y/=GCD; Z/=GCD; P/=GCD;
exgcd(Y,P,x,y,d);
x=(x%P+P)%P;
x=x*Z%P;
printf("%lld\n",x);
break;
}
case 3:{
if (Y%P==0){
printf("Orz, I cannot find x!\n");
continue;
}
hash.clear();
pd=false;
m=ceil(sqrt(P));
Y_m=fast_pow(Y,m);
mul=1;
now=mul*Z;
hash[now]=0;
for (int j=1;j<=m;++j){
mul=mul*Y%P;
now=mul*Z%P;
hash[now]=j;
}
mul=1;
for (int i=1;i<=m;++i){
mul=mul*Y_m%P;
if (hash[mul]){
pd=true;
ans=i*m-hash[mul];
printf("%lld\n",ans);
break;
}
}
if (!pd) printf("Orz, I cannot find x!\n");
break;
}
}
}
}