题目描述
传送门
题目描述有问题!
y,z,p
中只有
p
为质数!
题目描述有问题!
题目描述有问题!
重要的事情说三遍!
题解
对于操作1:
快速幂而已,不存在无解的情况。
对于操作2:
扩展欧几里得算法。有解的条件为:
证明:
已知
xy≡z(modp)
原式可化为:
xy−ap=z
问题可以转化为求是否有一组数x,a使 xy−ap=z
而如果把所有x,a的取值以及对应的 xy−ap 的得数建系的话,会发现最小的数为x,a的gcd,而其他所有的数都为gcd的倍数。
这样我们就可以得出:有解的条件为: gcd(y,p)|z
我们知道当
(y,p)=1
时我们可以利用扩展欧几里得求出
xy−ap=gcd(y,p)
即
xy−ap=1
的解
x,a
所以将原式转换一下:
xzy+azp=1
令 xz=x′,az=a′ ,求出x’和a’的值再与z相乘即为答案。
有人有问题吗?
能用扩展欧几里得求这个式子
xzy+azp=1
的解条件不是y,p互质吗?那要不要判断一下呢?
其实是不用的,因为如果满足这个式子
gcd(y,p)|z
的话,我们可以让等式两边同时/gcd(y,p),也就是y,z,p同时/gcd(y,p)。这样的话就保证了y,p一定互质啦。
对于操作3:
只是BSGS算法的模板啦,可以参考本博客BSGS算法学习笔记。
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
int T,type;
LL y,z,p,ans;
map <LL,LL> 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;
}
}
}
}