题目大意:三合一,给你$y,z,p$,求$x$,三种询问
- $y^z\bmod{p}$
- $xy\equiv z\pmod p$的最小非负整数
- $y^z\equiv z\pmod p$的最小非负整数
题解:求快速幂,逆元和$BSGS(离散对数)$
$BSGS$就是用分块的思想,令$m=\lceil \sqrt p\rceil$,因为$y^{i\times m+j}=y^{i\times m}\times y^j$所以可以预处理$y^i$(用$hash$或$map(加复杂度和大常数,但是方便。。。)$ $(unordered\_map是C++11的,考前还是不要用了吧)$,然后枚举$i$,求出$y^{i\times m}$,找一下有没有对应的$y^j$就行了
卡点:无
C++ Code:
#include <cstdio>
#include <cmath>
#include <map>
long long T, k;
long long y, z, p;
namespace calc1 {
long long calc (long long base, long long p, long long mod) {
base %= mod, p %= mod - 1;
long long ans = 1;
for (; p; p >>= 1, base = base * base % mod) if (p & 1) ans = ans * base % mod;
return ans;
}
long long inv(long long a, long long mod) {
return calc(a, mod - 2, mod);
}
}
namespace calc2 {
long long calc (long long y, long long z, long long mod) {
y %= mod, z %= mod;
if (!y) return z ? -1 : 0;
long long tmp = calc1::inv(y, mod);
return tmp * z % mod;
}
}
namespace calc3 {
std::map<int, int> mp;
long long calc(long long y, long long z, long long mod) {
y %= mod, z %= mod;
if (!y) return -1;
long long tmp = 1, t = sqrt(mod - 1) + 1;
mp.clear();
for (int i = 0; i <= t; i++) {
mp[tmp * z % mod] = i;
if (i != t) tmp = tmp * y % mod;
}
long long tmp6 = tmp;
for (int i = 1; i <= t; i++) {
if (mp.count(tmp6)) return i * t - mp[tmp6];
tmp6 = tmp6 * tmp % mod;
}
return -1;
}
}
int main() {
scanf("%lld%lld", &T, &k);
while (T --> 0) {
scanf("%lld%lld%lld", &y, &z, &p);
long long tmp;
switch (k) {
case 1: tmp = calc1::calc(y, z, p); break;
case 2: tmp = calc2::calc(y, z, p); break;
case 3: tmp = calc3::calc(y, z, p); break;
}
if (tmp == -1) puts("Orz, I cannot find x!");
else printf("%lld\n", tmp);
}
}