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)的最小非负整数。
Solution
第一问瞎搞,第二问因为p是质数因此求一下逆元即可。如果不是质数的话可以考虑exgcd
第三问是BSGS
设
x=ti−j
x
=
t
i
−
j
,则
Yti−j≡Z(modP)
Y
t
i
−
j
≡
Z
(
m
o
d
P
)
,移项得
Yti≡ZYj(modP)
Y
t
i
≡
Z
Y
j
(
mod
P
)
可以先枚举j用map记录,然后枚举i判断是否存在一个
ZYj
Z
Y
j
就ok。显然t取
P−−√
P
比较优秀
证明:由
YP−1≡1(modP)
Y
P
−
1
≡
1
(
mod
P
)
可知这里存在一个循环,x最大取到p
洛谷能a但是bzoj死活过不了,难拍,留坑
Code
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <map>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
std:: map <int, int> map;
LL ksm(LL x,int dep,int mod) {
if (dep==0) return 1;
if (dep==1) return x;
LL tmp=ksm(x,dep/2,mod);
if (dep%2) return tmp*tmp%mod*x%mod;
else return tmp*tmp%mod;
}
void solve1(int a,int b,int c) {
printf("%lld\n", ksm((LL)a,b,c)%c);
}
void solve2(int a,int b,int c) {
b=b%c;
if (a==0&&b!=0) {
puts("Orz, I cannot find x!");
return ;
}
LL ans=ksm(a,c-2,c)*(LL)b%c;
while (ans<0) ans=(ans+c)%c;
printf("%lld\n", ans);
}
void solve3(LL a,LL b,LL c) {
if (a+b==0) {
puts("1");
return ;
}
if (a+b==b) {
puts("Orz, I cannot find x!");
return ;
}
map.clear();
int m=(int)ceil(sqrt(c));
rep(i,0,m) {
int x=ksm(a,i,c)*b%c;
map[x]=i;
}
rep(i,1,m) {
LL x=ksm(a,m*i,c);
if (map[x]) {
LL ans=i*m-map[x];
while (ans<0) ans=(ans+c)%c;
printf("%lld\n", ans);
return ;
}
}
puts("Orz, I cannot find x!");
}
int main(void) {
int n,m; scanf("%d%d",&n,&m);
while (n--) {
LL a,b,c; scanf("%lld%lld%lld",&a,&b,&c);
a=a%c;
if (m==1) {
solve1(a,b,c);
} else if (m==2) {
solve2(a,b,c);
} else if (m==3) {
solve3(a,b,c);
}
}
return 0;
}