Description
你被要求设计一个计算器完成以下三项任务:
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)的最小非负整数。
Input
输入包含多组数据。
第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。
Output
对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。
Sample Input
【样例输入1】
3 1
2 1 3
2 2 3
2 3 3
【样例输入2】
3 2
2 1 3
2 2 3
2 3 3
【数据规模和约定】
对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。
Sample Output
【样例输出1】
2
1
2
【样例输出2】
2
1
0
分析
第一问快速幂
第二问exgcd
第三问BSGS,好麻烦我就先略
为啥叫baby step giant step,我其实不是很懂
卓神说这是meet in the middle的一种运用
求
yx=z(modp)
设
x=km+i
ykm∗yi≡z
yi≡z∗ine(ykm)
(逆元)
用费马小定理显然可得
ine(ym)≡yp−1−m
设其为
ine(ykm)≡ine(y(k−1)m)∗T
把
yi(0<=i<=m)
放入hash或者map
然后枚举k,查询
z∗ine(ykm)
显然m取
p√
复杂度比较优秀
代码
#include <bits/stdc++.h>
#define INF 0x7fffffff
#define ll long long
int T,K;
int read()
{
int x = 0,k = 1;
char ch= getchar();
while (ch<'0' || ch > '9')
{
ch = getchar();
if (ch == '-')
k = -1;
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * k;
}
int gcd(int a,int b)
{
return b == 0 ? a : gcd(b,a % b);
}
void exgcd(int a,int b,int &x,int &y)
{
if (b == 0)
{
x = 1;
y = 0;
return ;
}
exgcd(b,a % b,x,y);
int t = x;
x = y;
y = t - a / b * y;
}
int pow(ll y,int z,int p)
{
y %= p;
ll ans = 1;
while (z)
{
if (z & 1)
ans = ans * y % p;
y = y * y % p;
z >>= 1;
}
return ans;
}
void slove(int y,int z,int p)
{
p = -p;
int t = gcd(y,p);
if (z % t)
{
printf("Orz, I cannot find x!\n");
return;
}
y /= t;
z /= t;
p /= t;
int a,b;
exgcd(y,p,a,b);
a = (ll)a * z % p;
while (a < 0)
a += p;
printf("%d\n",a);
}
std::map<int,int> M;
void BSGS(int y,int z,int p)
{
y %= p;
if (!y && !z)
{
printf("1\n");
return;
}
if (!y)
{
printf("Orz, I cannot find x!\n");
return;
}
M.clear();
ll m = ceil(sqrt(p)),t = 1;
M[1] = m + 1;
for (ll i = 1; i < m; i++)
{
t = t * y % p;
if (!M[t])
M[t] = i;
}
ll tmp = pow(y,p - m - 1,p);
ll ine = 1;
for (ll k = 0; k < m; k++)
{
int i = M[z * ine % p];
if (i)
{
if (i == m + 1)
i = 0;
printf("%lld\n",k * m + i);
return ;
}
ine = ine * tmp % p;
}
printf("Orz, I cannot find x!\n");
}
int main()
{
T = read();
K = read();
while (T--)
{
int y = read(),z = read(),p = read();
if (K == 1)
printf("%d\n",pow(y,z,p));
else if (K == 2)
slove(y,z,p);
else BSGS(y,z,p);
}
}