Problem
Solution
对于第一种操作,快速幂即可。
对于第二种操作,等式两边同乘在模p意义下的y的逆元inv(y),则等式变为x≡(z×inv(y))%p (mod p)。
对于第三种操作,用BSGS。
BSGS利用了分块的思想,首先我们由费马小定理知道
yp−1≡1(modp)
y
p
−
1
≡
1
(
m
o
d
p
)
,也就是说只需要枚举到p-1即可,但我们希望优化。那么设m=ceil(sqrt(p)),则x可表示为km+i。也就是说
akm×ai≡b(modp)
a
k
m
×
a
i
≡
b
(
m
o
d
p
)
。为了方便查表,我们用hash将a^i存起来。
法一:扩展欧几里得
不妨设
D=akm
D
=
a
k
m
,则
D×ai≡b(modp)
D
×
a
i
≡
b
(
m
o
d
p
)
。扩欧求解A^i,然后查表看存不存在。
法二:逆元
就相当于
ai≡b×inv(akm)(modp)
a
i
≡
b
×
i
n
v
(
a
k
m
)
(
m
o
d
p
)
。每次k自增时,等式两边同乘inv(a^m),然后查表。较法一快,逆元用费马小定理求即可。下方代码中用的是法二。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const ll MAXX=((1<<30)-1)<<1|1;
struct hashtable{
static const ll ha=999917,maxe=46340;
ll E,lnk[ha],son[maxe+5],nxt[maxe+5],w[maxe+5];
ll top,stk[maxe+5];
void clear(){E=0;while(top) lnk[stk[top--]]=0;}
void add(ll x,ll y){son[++E]=y;nxt[E]=lnk[x];w[E]=MAXX;lnk[x]=E;}
bool count(ll y)
{
ll x=y%ha;
for(int j=lnk[x];j;j=nxt[j]) if(y==son[j]) return true;
return false;
}
ll& operator [] (ll y)
{
ll x=y%ha;
for(int j=lnk[x];j;j=nxt[j]) if(y==son[j]) return w[j];
add(x,y);stk[++top]=x;return w[E];
}
}f;
ll n,k,ans,y,z,p;
inline ll min(int x,int y){return x<y?x:y;}
ll power(ll x,ll y,ll p)
{
ll res=1;
while(y)
{
if(y&1) res=res*x%p;
x=x*x%p;
y>>=1;
}
return res;
}
ll bsgs(ll a,ll b,ll c)
{
if(c==1) return b?-1:(a!=1);
if(b==1) return a?0:-1;
if(a%c==0) return b?-1:1;
ll m=ceil(sqrt(c+0.5)),base=1;ll v=power(a,c-m-1,c);
f.clear();
for(int i=0;i<=m-1;i++)
{
f[base]=min(f[base],i);
base=(base*a)%c;
}
for(int i=0;i<=m-1;i++)
{
if(f.count(b)) return i*m+f[b];
b=b*v%c;
}
return -1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
scanf("%lld%lld",&n,&k);
while(n--)
{
scanf("%lld%lld%lld",&y,&z,&p);
switch(k)
{
case 1:printf("%lld\n",power(y,z,p));break;
case 2:
if(z%p==0){puts("0");break;}
else if(y%p==0){puts("Orz, I cannot find x!");break;}
printf("%lld\n",((z%p)*power(y,p-2,p))%p);break;
case 3:
ans=bsgs(y,z,p);
if(~ans) printf("%lld\n",ans);
else puts("Orz, I cannot find x!");
break;
}
}
return 0;
}