1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<cmath> 5 #define ll long long 6 using namespace std; 7 ll T,k,y,z,p; 8 map<int,int> mp; 9 void exgcd(int a1,int a2,ll &x,ll &y) 10 { 11 if(!a2) 12 { 13 x=1; 14 y=0; 15 return; 16 } 17 exgcd(a2,a1%a2,x,y); 18 int t=x; 19 x=y; 20 y=t-a1/a2*y; 21 } 22 ll gcd(ll a1,ll a2) 23 { 24 for(;a2;) 25 { 26 ll a3=a1%a2; 27 a1=a2; 28 a2=a3; 29 } 30 return a1; 31 } 32 ll kuai(ll y,ll z) 33 { 34 ll ans=1; 35 for(;z;) 36 { 37 if(z%2) 38 ans=(ans*y)%p; 39 y=(y*y)%p; 40 z=z/2; 41 } 42 return ans; 43 } 44 bool pan(ll y,ll z,ll p) 45 { 46 mp.clear(); 47 ll m=ceil(sqrt(p)),t=1; 48 mp[1]=m+1; 49 for(ll i=1;i<m;i++) 50 { 51 t=t*y%p; 52 mp[t]=i; 53 } 54 ll T=kuai(y,p-m-1),ine=1; 55 for(int k=0;k<=m;k++) 56 { 57 int i=mp[z*ine%p]; 58 if(i) 59 { 60 if(i==m+1) 61 i=0; 62 printf("%lld ",k*m+i); 63 return 1; 64 } 65 ine=ine*T%p; 66 } 67 return 0; 68 } 69 int main() 70 { 71 scanf("%lld%lld",&T,&k); 72 for(int i=1;i<=T;i++) 73 { 74 scanf("%lld%lld%lld",&y,&z,&p); 75 if(k==1) 76 printf("%lld ",kuai(y,z)); 77 if(k==2) 78 { 79 ll x1,y1; 80 ll t=gcd(y,p); 81 if(z%t) 82 { 83 printf("Orz, I cannot find x! "); 84 continue; 85 } 86 y/=t; 87 p/=t; 88 z/=t; 89 exgcd(y,p,x1,y1); 90 x1=(x1*z)%p; 91 for(;x1<0;) 92 x1+=p; 93 printf("%lld ",x1); 94 } 95 if(k==3) 96 { 97 y%=p; 98 z%=p; 99 if(!y&&!z) 100 { 101 printf("1 "); 102 continue; 103 } 104 if(!y) 105 { 106 printf("Orz, I cannot find x! "); 107 continue; 108 } 109 if(!pan(y,z,p)) 110 printf("Orz, I cannot find x! "); 111 } 112 } 113 return 0; 114 }
第一种情况 快速幂 第二种情况 exgcd 第三种情况 大步小步法 把x变成k*m+i,把所有的0-m次方用map存下来,然后依次累加k,直到找到一个可行的。