牛客20347 SDOI2011计算器(bsgs
https://ac.nowcoder.com/acm/problem/20347
这篇是为了补bsgs(北上广深算法)。
题意:
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)的最小非负整数。
思路:
1.当然是裸的快速幂取模啦。
2.原式<=>yx+pk=z有解,exgcd记录d=gcd(y,p),看是否d|z即可。
3.要求满足形如a^x ≡ b (mod p)的最小非负整数x。
由周期性只需在[0,p)讨论即可,证明的话,抽屉原理显然,或者由费马小定理( 当p为质数且(a,p)=1时 a^(p-1)=1 (mod p) )能推出a^k=a^(k mod (p-1)) (mod p)。
把x分块,每块长度是m,其中m=ceil(sqrt(p)),则a^(i*m-j) = b (mod p),移项得a^(i*m) = b*a^j (mod p)
枚举j(范围0-m),将b*a^j存入哈希表。
枚举i(范围1-m),从哈希表找出第一个满足a^(i*m) = b*a^j (mod p)的i
此时x = i*m-j就是答案
时间复杂度O(m+p/m),m取√p时最优。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 int T,k,a,b,p; 5 map<int,int>mp; 6 7 int kuai(int a,int b,int mod) 8 { 9 if(b==1)return a; 10 int x=kuai(a,b/2,mod); 11 if(b%2==0)return x*x%mod; 12 else return x*x%mod*a%mod; 13 } 14 15 void exgcd(int a,int b,int &d,int &x,int &y) 16 { 17 if(b==0){d=a;x=1;y=0;} 18 else{exgcd(b,a%b,d,y,x);y-=x*(a/b);} 19 } 20 21 int bsgs(int a,int b,int p){ 22 a%=p;b%=p; 23 if(!a&&!b) return 1; 24 if(!a||!b) return -1; 25 mp.clear(); 26 int m = ceil(sqrt(1.0*p)),tmp=1; 27 mp[tmp*b%p]=0; 28 for(int j=1;j<=m;j++){ 29 tmp = tmp*a%p; 30 if(!mp[tmp*b%p]) mp[tmp*b%p] = j; 31 } 32 int t = 1,ans; 33 for(int i=1;i<=m;i++){ 34 t=t*tmp%p; 35 if(mp[t]){ 36 ans = i*m-mp[t]; 37 return (ans%p+p)%p; 38 } 39 } 40 return -1; 41 } 42 43 signed main(){ 44 45 scanf("%lld%lld",&T,&k); 46 while(T--) 47 { 48 scanf("%lld%lld%lld",&a,&b,&p); 49 if(k==1)printf("%lld\n",kuai(a,b,p)%p); 50 else if(k==2) 51 { 52 int x=0,y=0,d; 53 exgcd(a,p,d,x,y); 54 if(b%d) 55 { 56 puts("Orz, I cannot find x!"); 57 continue; 58 } 59 x=x*b/d; 60 x=(x%p+p)%p; 61 printf("%lld\n",x); 62 } 63 else{ 64 int ans=bsgs(a,b,p); 65 if(ans==-1)puts("Orz, I cannot find x!"); 66 else printf("%lld\n",ans); 67 } 68 } 69 return 0; 70 }