题意:有三种要求:
1、给定y,z,p,计算Y^Z Mod P 的值;
2、给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数;
3、给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数。
分别处理即可
思路:
1显然是快速幂了,纯模板
2是扩展欧几里得(exgcd),求满足xy-pk=z的最小x(k任意)
3利用了费马小定理的性质a^(p-1)≡1(mod p),然后分块降复杂度(太麻烦懒得写直接抄黄学长代码…捂脸)
/**************************************************************
Problem: 2242
User: Rainbow6174
Language: C++
Result: Accepted
Time:2028 ms
Memory:3272 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
int T,k;
map<int,int> vis;
LL y,z,x,a,b,m,t,mod,temp,flag;
LL pow(LL base,LL x)
{
LL ret = 1;
base %= mod;
while(x)
{
if(x & 1)ret *= base,ret %= mod;
base *= base;
base %= mod;
x >>= 1;
}
return ret;
}
LL gcd(LL x,LL y)
{
if(!y)return x;
return gcd(y,x%y);
}
LL exgcd(LL x,LL y)
{
if(!y)
{
a=1,b=0;
return x;
}
int ret=exgcd(y,x%y);
//cout<<a<<' '<<b<<' '<<x<<' '<<y<<endl;
temp=a;
a=b;
b=temp-(x/y)*b;
return ret;
}
int main(void)
{
//freopen("calc.in","r",stdin);
//freopen("calc.out","w",stdout);
scanf("%d%d",&T,&k);
while(T--)
{
scanf("%lld%lld%lld",&y,&z,&mod);
if(k==1)printf("%lld\n",pow(y,z));
y%=mod;
z%=mod;
if(k==2)
{
if(!z)
{
printf("0\n");
continue;
}
if(!y || gcd(y,mod)>z)
{
printf("Orz, I cannot find x!\n");
continue;
}
//cout<<y<<' '<<mod<<endl;
exgcd(y,mod);
a+=mod;
a%=mod;
a*=z/gcd(y,mod);
a%=mod;
printf("%lld\n",a);
}
if(k==3)
{
flag=0;
if(!y)
{
if(!z)puts("1");
else puts("Orz, I cannot find x!");
continue;
}
vis.clear();
LL a=ceil(sqrt(mod)),t=1;
vis[1]=a+1;
for(LL i=1;i<a;i++)
{
t=t*y%mod;
if(!vis[t])vis[t]=i;
}
temp=pow(y,mod-a-1),b=1;
for(LL i=0;i<a;i++)
{
int temp1=vis[z*b%mod];
if(temp1)
{
if(temp1==a+1)temp1=0;
printf("%lld\n",i*a+temp1);
flag=1;
break;
}
b=b*temp%mod;
}
if(!flag)puts("Orz, I cannot find x!");
}
}
}