Jzoj2270 【SDOI2011】计算器
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)的最小非负整数 。
2、给定 y、z、p,计算满足xy≡z(mod p)的最小非负整数 ;
3、给定y、z、p,计算满足y^x≡z(mod p)的最小非负整数 。
第一问不说,第二问请看 同余方程 主要说第三问
第三问是经典的离散对数(其实我并不会而且也基本不考)
我们使用经典的giant-step-baby-step算法,令s=sqrt(m),那么x=ks+r,我们将所有y^r放进map中
让后枚举k,对于一个k,我们查找z*inv(y^ks)是否在map中有解,如果有那么直接返回r+ks
#include<stdio.h> #include<math.h> #include<map> using namespace std; #define L long long L x,y,z,M; int n,t; L pow(L x,L k){ L S=1; for(;k;x=x*x%M,k>>=1) if(k&1) S=S*x%M; return S; } L extgcd(L a,L b,L& x,L& y){ if(b){ L r=extgcd(b,a%b,y,x); y-=x*(a/b); return r; } else { x=1,y=0; return a; } } L sol(L a,L b){ L x,y,r=extgcd(a,M,x,y); if(b%r) return -1; else { x*=b/r; x=(M-x)%M; x=(M-x)%M; return (x+M)%(M/r); } } L dislog(int x,int n){ if(x==0) return -1; if(n%M==1) return 0; map<L,int> rec; L c=1,mul; int sq=sqrt(M); for(;1ll*sq*sq<=M;++sq); for(int i=0;i<sq;++i){ rec[c]=i; c=c*x%M; } mul=c; c=1; for(int i=0;i<sq;++i){ L m=1ll*n*pow(c,M-2)%M; if(rec[m]) return (M+i*sq+rec[m])%M; c=c*mul%M; } return -1; } int main(){ scanf("%d%d",&n,&t); for(int i=0;i<n;++i){ scanf("%lld%lld%lld",&y,&z,&M); if(t==1) printf("%lld\n",pow(y,z)); if(t==2) { L ans=sol(y,z); if(~ans) printf("%lld\n",ans); else puts("Orz, I cannot find x!"); } if(t==3) { z%=M;y%=M; L ans=dislog(y,z); if(~ans) printf("%lld\n",ans); else puts("Orz, I cannot find x!"); } } }