P4195 【模板】exBSGS/Spoj3105 Mod
首先要懂得 $BSGS$,$BSGS$ 可以求出关于 $Y$ 的方程 $X^Y \equiv Z (mod\ mo)$ 的最小解,其中 $gcd(X,Z)=1$
$exBSGS$ 算是 $BSGS$ 的进一步扩展,使得当 $gcd(X,Z)!=1$ 时仍然适用
先把方程转换成 $X^Y+k*mo=Z$ 的形式
因为 $Y,k$ 都是整数,所以 $Z$ 必须是 $gcd(X,mo)$ 的倍数,不然无解
所以可以把方程左右同除 $gcd(X,mo)$,变成 $X^{(Y-1)}*\frac{X}{gcd(X,mo)}+k*\frac{mo}{gcd(X,mo)}=\frac{Z}{gcd(X,mo)}$
其实这个方程就相当于 $\frac{X}{gcd(X,mo)}*X^{(Y-1)} \equiv \frac{Z}{gcd(X,mo)} (mod\ \frac{mo}{gcd(X,mo)})$
发现 $\frac{X}{gcd(X,mo)}$ 只是一个系数,如果此时 $gcd(X,\frac{mo}{gcd(X,mo)})=1$ 则可以直接套用 $BSGS$ 求解
如果此时 $gcd(X,\frac{mo}{gcd(X,mo)})!=1$ 则可以继续上述操作直到 $gcd$ 为 $1$
设第 $i$ 次操作的 $gcd$ 为 $d_i$,总共进行了 $T$ 次操作
则最后式子的形式为 $\frac{X^T}{\prod _{i=1}^{T}d_i}X^{Y-T} \equiv \frac{Z}{\prod _{i=1}^{T}d_i}\ \ (mod\ \frac{mo}{\prod _{i=1}^{T}d_i})$
要记得特判 $Y \in [0,T]$ 的情况
具体看代码
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<map> using namespace std; typedef long long ll; typedef long double ldb; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int gcd(int a,int b) { return b ? gcd(b,a%b) : a; } map <int,int> mp; inline int ksm(int x,int y,int mo) { int res=1; while(y) { if(y&1) res=1ll*res*x%mo; x=1ll*x*x%mo; y>>=1; } return res; } // X^Y=Z (mod mo) void exBSGS(int X,int Z,int mo) { if(Z==1) { printf("0\n"); return; } int d=gcd(X,mo),t=0,k=1; while(d!=1) { if(Z%d) { printf("No Solution\n"); return; } t++; k=(1ll*k*(X/d))%mo; mo/=d; Z/=d; if(k==Z) { printf("%d\n",t); return; } d=gcd(X,mo); } int m=sqrt(mo)+1; mp.clear(); for(int b=0,s=Z; b<m; b++,s=1ll*s*X%mo) mp[s]=b; for(int a=1,p=ksm(X,m,mo),s=1ll*k*p%mo; a<=m+1; a++,s=1ll*s*p%mo) { if(mp.find(s)==mp.end()) continue; printf("%d\n",a*m-mp[s]+t); return; } printf("No Solution\n"); } int main() { int X=read(),mo=read(),Z=read(); while(X||Z||mo) { exBSGS(X,Z,mo); X=read(),mo=read(),Z=read(); } return 0; }