作用:求形如A^x==B(mod P)
考虑由BSGS----->exBSGS
BSGS:
(A与P互质)A^phi(P)==1(mod P),A^0==1(modP),感性理解,是个循环,
考虑分块,设A^(ky+b)==B(mod P)。
即(A^y)^k*A^b==B(mod P)------>A^b==B*inv((A^y)^k)(mod P);设y==sqrt(P);(phi(P)更好,但是P也行,主要是懒)
将A^g(0<=g<y)hash出,再每次判断即可。
exBSGS:
设 r=gcd(A,P),p=A/r,q=P/r;
首先考虑无解的情况(B%r!=0&&B!=1)
B=(r*p)^x+w*q*r=(r^x)*(p^x)+w*q*r=r*(r^(x-1))*p^x+r*q*w=r*(r^(x-1)*p^x+w*q);
若B==1,A^0==1;
所以,若(B%r!=0&&B!=1),则无解;
使A,P互质需要除去公因数,设b=B/r,
A*A^(x-1)==B(mod P)——>
P=q,B=b;
p*A^(x-1)==B(mod P)——>A^(x-1)=B*inv(p)(mod P);
循环此过程,直至A与P互质即可。
例题:https://www.luogu.org/problemnew/show/P4195
#include<cstdio> #include<ctype.h> #include<iostream> #include<cmath> using namespace std; #define ll long long inline ll rd() { ll x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-') f=-f;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return x*f; } const int N=1e5,mod=99991; int P,vis[N],h[N],nxt[N],val[N]; ll exgcd(ll &x,ll &y,ll a,ll b) { if(!b){x=1;y=0;return a;} int t=exgcd(x,y,b,a%b),w=x;x=y;y=w-(a/b)*x; return t; } ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll bsgs(ll a,ll b,ll w) { ll x,y,p=ceil(sqrt(P)),q,op=-1,i,j;exgcd(x,y,w,P);b=(b*x%P+P)%P; for(i=1,j=0;j<p;j++,i=i*a%P) val[j+1]=i,x=i%mod,nxt[j+1]=h[x],h[x]=j+1; exgcd(x,y,i,P);q=(x%P+P)%P; for(i=b,j=0;j<=p;j++,i=i*q%P) {x=i%mod;for(y=h[x];y;y=nxt[y])if(val[y]==i)op=p*j+y-1;if(op!=-1) break;} for(i=1,j=0;j<p;j++,i=i*a%P) h[i%mod]=0; return op; } ll exbsgs(int a,int b) { ll c,k=0,w=1;if(b==1) return 0; while((c=gcd(a,P))>1){if(b%c) return -1;b/=c;P/=c;w=w*(a/c)%P;k++;if(w==b) return k;} return (c=bsgs(a,b,w))==-1?-1:c+k; } int main() { while(1) { int a=rd(),b;ll c;P=rd();b=rd();if(!a&&!b&&!P) return 0; if((c=exbsgs(a,b))==-1) printf("No Solution ");else printf("%lld ",c); } }