bzoj 2242 [SDOI2011]计算器(数论知识)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2242 [SDOI2011]计算器(数论知识)相关的知识,希望对你有一定的参考价值。
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。
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
2
1
2
【样例输出2】
2
1
0
【思路】
快速幂,拓展欧几里得,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 }
以上是关于bzoj 2242 [SDOI2011]计算器(数论知识)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj千题计划246:bzoj2242: [SDOI2011]计算器