传送门
题目描述有问题! 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
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
int T,type;
LL y,z,p,ans;
map hash;
LL fast_pow(LL a,LL p,LL Mod)
{
LL ans=1;
for (;p;p>>=1LL,a=a*a%Mod)
if (p&1LL)
ans=ans*a%Mod;
return ans;
}
LL gcd(LL a,LL b)
{
if (!b) return a;
else return gcd(b,a%b);
}
void exgcd(LL a,LL b,LL &x,LL &y)
{
if (!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
LL EXgcd(LL a,LL b,LL c)
{
LL t=gcd(a,b);
if (c%t) return -1;
a/=t,b/=t,c/=t;
LL x=0,y=0;
exgcd(a,b,x,y);
x=(x%b+b)%b;
if (!x) x+=b;
return (x*c%b+b)%b;
}
LL bsgs(LL a,LL b,LL p)
{
if (a%p==0) return -1;
hash.clear();
LL m=ceil(sqrt(p));
LL a_m=fast_pow(a,m,p);
LL mul=b;
for (LL j=0;j<=m;++j)
{
hash[mul]=j+1;
mul=mul*a%p;
}
mul=1;
for (LL i=1;i<=m;++i)
{
mul=mul*a_m%p;
if (hash[mul]) return i*m-(hash[mul]-1);
}
return -1;
}
int main()
{
scanf("%d%d",&T,&type);
while (T--)
{
scanf("%lld%lld%lld",&y,&z,&p);
switch(type)
{
case 1:
{
ans=fast_pow(y,z,p);
printf("%lld\n",ans);
break;
}
case 2:
{
ans=EXgcd(y,p,z);
if (ans==-1) puts("Orz, I cannot find x!");
else printf("%lld\n",ans);
break;
}
case 3:
{
ans=bsgs(y,z,p);
if (ans==-1) puts("Orz, I cannot find x!");
else printf("%lld\n",ans);
break;
}
}
}
}