你被要求设计一个计算器完成以下三项任务:
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)的最小非负整数。
标签:
输入包含多组数据。
【思路】
快速幂,拓展欧几里得,BSGS
第一问快速幂求得。
第二问求axΞ b(mod n),转化为ax=ny+b,转化为ax+ny=b,利用拓展欧几里得算法求出ax+ny=gcd(a,n),如果b不是gcd的倍数则无解否则为x/gcd*b。
第三问求ax Ξb(mod n),BSGS算法。我们需要验证0..n-1内的数。分块,设每块大小为m,求出0..m-1内的ai % n保存为ei,对于m..2m-1内的数,我们只需要验证是否存在有am *ei=b(mod n),即判断是否存在ei=a-m *b (mod n),这样用一个hash表存一下ei然后求一下在模n下am的逆元就可以了。
时间复杂度为O((m+n/m)logm),当m取n½的时候复杂度较优为O(n½logn)
【代码】
1 #include<map> 2 #include<cmath> 3 #include<cstdio> 4 using namespace std; 5 6 typedef long long LL; 7 LL a,b,c,T,k; 8 9 LL pow(LL x,LL p,LL MOD) { 10 LL tmp=x,ans=1; 11 while(p) { 12 if(p&1) ans=(ans*tmp)%MOD; 13 tmp=(tmp*tmp)%MOD; 14 p>>=1; 15 } 16 return ans; 17 } 18 void gcd(LL a,LL b,LL& d,LL& x,LL& y) { 19 if(!b) d=a,x=1,y=0; 20 else gcd(b,a%b,d,y,x),y-=x*(a/b); 21 } 22 LL inv(LL a,LL n) { 23 LL d,x,y; 24 gcd(a,n,d,x,y); 25 return d==1? (x+n)%n:-1; 26 } 27 LL log_mod(LL a,LL b,LL n) { 28 LL m,v,e=1,i; 29 m=sqrt(n+0.5); 30 v=inv(pow(a,m,n),n); 31 map<LL,LL> mp; 32 mp[1]=0; 33 for(LL i=1;i<m;i++) { 34 e=(e*a)%n; 35 if(!mp.count(e)) mp[e]=i; 36 } 37 for(LL i=0;i<m;i++) { 38 if(mp.count(b)) return i*m+mp[b]; 39 b=(b*v)%n; 40 } 41 return -1; 42 } 43 44 int main() { 45 scanf("%lld%lld",&T,&k); 46 while(T--) { 47 scanf("%lld%lld%lld",&a,&b,&c); 48 if(k==1) { 49 printf("%lld\n",pow(a,b,c)); 50 } else 51 if(k==2) { 52 LL d,x,y; 53 gcd(a,c,d,x,y); 54 if(b%d) puts("Orz, I cannot find x!"); 55 else { 56 LL ans=((x*b/d)%c+c)%c; 57 printf("%lld\n",ans); 58 } 59 } else { 60 LL ans=log_mod(a,b,c); 61 if(ans==-1) puts("Orz, I cannot find x!"); 62 else printf("%lld\n",ans); 63 } 64 } 65 return 0; 66 }
标签:
原文地址:http://www.cnblogs.com/lidaxin/p/5218069.html