版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq872425710/article/details/82869080
题目大意:
给你三个操作
1:求a^b=x(%p)
2:求a*b=x(%p)
3:求a^x=b(%p)
思路:
这是数论里面比较好的题了,第一问快速幂,第二问扩展gcd,第三问BSGS。
第三问a^x=b(%p),因为过p个肯定有一个循环节,飞马小定理可得,那么我们把x分成根号p块,设为a ^(i*m)a ^j=b(%p),移项可得
ine为逆元,左边的放到hash里面,然后计算右边的在hash里面找,找到了说明im+j就是答案了。
程序:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<cmath>
#define LL long long
using namespace std;
map<int,int> mp;
int t,k,y,z,p;
void exgcd(int a,int b,int &x,int &y){
if (!b){
x=1; y=0; return;
}
exgcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-a/b*y;
}
int gcd(int x,int y){
if (!y) return x;
return gcd(y,x%y);
}
int ksm(int x,int y,int mo){
if (y==1) return x;
if (!y) return 1;
int o=ksm(x,y/2,mo);
o=((LL)o*o)%mo;
if (y%2==1) o=((LL)o*x)%mo;
return o;
}
void solve1(int x,int y,int p){
printf("%d\n",ksm(x,y,p));
}
void solve2(int a,int z,int b){
int x,y;
int t=gcd(a,b);
if (z%t>0){
printf("Orz, I cannot find x!\n");
return;
}
exgcd(a,b,x,y);
if (x<0) x=(x+b)%b;
printf("%d\n",(LL)x*z%b);
}
void solve3(int y,int z,int p){
y%=p;
if (!y&&!z){
printf("%d\n",1);
return;
}
if (!y){
printf("Orz, I cannot find x!\n");
return;
}
mp.clear();
int m=ceil(sqrt(p)),t=1;
mp[1]=m+1;
for (int i=1;i<m;i++){
t=(LL)t*y%p;
if (!mp[t]) mp[t]=i;
}
int tmp=ksm(y,p-m-1,p),ine=1;
for (int i=0;i<m;i++){
int k=mp[(LL)z*ine%p];
if (k){
if (k==m+1) k=0;
printf("%d\n",i*m+k);
return;
}
ine=(LL)ine*tmp%p;
}
printf("Orz, I cannot find x!\n");
}
int main(){
scanf("%d%d",&t,&k);
for (int i=1;i<=t;i++){
scanf("%d%d%d",&y,&z,&p);
if (k==1) solve1(y,z,p);
if (k==2) solve2(y,z,p);
if (k==3) solve3(y,z,p);
}
}