传送门
数论基础题。
对于第一种情况用快速幂,第二种用exgcdexgcdexgcd,第三种用bsgsbsgsbsgs
于是自己瞎yyyyyy了一个bsgsbsgsbsgs的板子(不知道是不是数据水了没卡如果有找出错的希望指正谢谢)
下面谈谈我对这个方法的理解。
实际上跟网上说的差不多。
要解ax≡bmod  pa^x\equiv b\mod pax≡bmodp
相当于令p=k∗A+B,0≤B<pp=k*A+B,0\le B<pp=k∗A+B,0≤B<p
然后假设x=k′∗A+B′,0≤B′<px=k'*A+B',0\le B'<px=k′∗A+B′,0≤B′<p
那么(aA)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′即可,可以想到在AAA取sqrtpsqrt_psqrtp的时候最坏复杂度最优。
代码:
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#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;
}