传送门
数论基础题。
对于第一种情况用快速幂,第二种用 e x g c d exgcd exgcd,第三种用 b s g s bsgs bsgs
于是自己瞎 y y yy yy了一个 b s g s bsgs bsgs的板子(不知道是不是数据水了没卡如果有找出错的希望指正谢谢)
下面谈谈我对这个方法的理解。
实际上跟网上说的差不多。
要解 a x ≡ b m o d    p a^x\equiv b\mod p ax≡bmodp
相当于令 p = k ∗ A + B , 0 ≤ B < p p=k*A+B,0\le B<p p=k∗A+B,0≤B<p
然后假设 x = k ′ ∗ A + B ′ , 0 ≤ B ′ < p x=k'*A+B',0\le B'<p x=k′∗A+B′,0≤B′<p
那么 ( a A ) k ′ ≡ b ∗ ( a − 1 ) B ′ (a^A)^{k'}\equiv b*(a^-1)^{B'} (aA)k′≡b∗(a−1)B′
于是枚举 k ′ k' k′和 B ′ B' B′即可,可以想到在 A A A取 s q r t p sqrt_p sqrtp的时候最坏复杂度最优。
代码:
#include
#include
#define ri register int
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
typedef long long ll;
inline int ksm(int a,int p,int mod){int ret=1;for(;p;p>>=1,a=(ll)a*a%mod)if(p&1)ret=(ll)ret*a%mod;return ret;}
inline int gcd(int a,int b){while(b){int t=a;a=b,b=t%a;}return a;}
inline void exgcd(int a,int b,int&x,int&y){
if(!b){x=1,y=0;return;}
exgcd(b,a%b,x,y);
int t=x;
x=y,y=t-a/b*y;
}
inline int bsgs(int a,int b,int mod){
a%=mod,b%=mod;
if(!a&&!b)return 1;
if(!a)return -1;
tr1::unordered_map<int,int>S;
int sqr=ceil(sqrt(mod-1)),inv=ksm(a,mod-2,mod);
for(ri i=0,mul=b;i<sqr;++i,mul=(ll)mul*inv%mod)if(!S[mul])S[mul]=i?i:sqr;
a=ksm(a,sqr,mod);
for(ri i=0,mul=1;i*sqr<=mod;++i,mul=(ll)mul*a%mod)if(S[mul])return i*sqr+(S[mul])%sqr;
return -1;
}
int main(){
freopen("lx.in","r",stdin);
for(ri a,b,p,tt=read(),k=read();tt;--tt){
a=read(),b=read(),p=read();
if(k==1){cout<<ksm(a%p,b,p)<<'\n';continue;}
if(k==2){
a%=p,b%=p;
int g=gcd(a,p),x,y;
if(b%g){puts("Orz, I cannot find x!");continue;}
a/=g,b/=g,p/=g,exgcd(a,p,x,y),x=((ll)b*x%p+p)%p,cout<<x<<'\n';
continue;
}
int tmp;
if(~(tmp=bsgs(a,b,p)))cout<<tmp<<'\n';
else puts("Orz, I cannot find x!");
}
return 0;
}