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,P为质数,1<=T<=10。
Sample Output
【样例输出1】
2
1
2
【样例输出2】
2
1
0
Solution
这种强行拼题真的好吗...
(一道题当T1,T2,T3用)
其实是板子题来着
第一问显然直接快速幂,第二问是exgcd,第三问是bsgs
这里讲一下bsgs的过程:
\[ 已知量:Y\space P\space Z\space m\\ Y^x\space \equiv Z\space (mod\space p)\\ 求x\\ 设m=\lceil \sqrt{P} \rceil\\ 则x=i*m-j \\ Y^{i*m-j}\equiv Z(mod\space P)\\ Y^{i*m}\equiv(Z*Y^j) (mod\space P)\\ \]
所以只需要开一个map,存一下\(Z*Y^j\)的值,然后枚举i,第一个枚举出来的答案就是最小值
#include <bits/stdc++.h>
#define ll long long
int T, k;
ll y, z, p;
ll power(ll a, ll b) {
ll ans = 1, base = a;
while(b) {
if(b & 1) ans = (ans * base) % p;
base = (base * base) % p;
b >>= 1;
}
return ans % p;
}
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) {return x = 1, y = 0, a;}
ll ans = exgcd(b, a % b, x, y), tmp = x;
x = y; y = tmp - (a / b) * y;
return ans;
}
std::map<ll , ll> mp;
void bsgs() {
mp.clear(); z %= p;
ll m = std::sqrt(p); if(m % p) ++ m;
for(ll i = 0, tmp = 1; i <= m; i ++, tmp = tmp * y % p) {
mp[z * tmp % p] = i;
}
if(power(y , m) == 0) {
if(z == 1) puts("1");
else puts("Orz, I cannot find x!");
return;
}
for(ll i = 1; i <= m; i ++) {
ll tmp = power(y, i * m), j = mp[tmp];
if(j == 0) continue;
if(i * m - j >= 0) {
printf("%lld\n", i * m - j);
return;
}
}
puts("Orz, I cannot find x!");
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
scanf("%d%d", &T, &k);
while(T--) {
scanf("%lld%lld%lld", &y, &z, &p);
if(k == 1) {
printf("%lld\n", power(y, z));
} else if(k == 2) {
ll a1, a2, g;
y %= p; z %= p;
g = exgcd(y ,p ,a1 ,a2);
if(z % g) puts("Orz, I cannot find x!");
else {
ll tmp = p / g;
a1 = ((a1 * z) % tmp + tmp) % tmp;
printf("%lld\n", a1);
}
} else bsgs();
}
return 0;
}