离散对数就是解方程:
$$求最小的非负整数x满足,a^x \equiv b(mod n)$$
我们先谈论简单一点的,$gcd(a,n)=1$的情况:
$$求最小的非负整数x满足,a^x \equiv b(mod n),其中gcd(a,n)=1$$
记$m=\left \lfloor \sqrt{n} \right \rfloor$
那么$x$一定可以表示为$x=im+j(0\leq i\leq m,0\leq j< m)$
变形一下:
$a^{im+j} \equiv b(mod n)$
$a^{im}\equiv ba^{-j}(mod n)$
我们先用一个map保存所有$ba^{-j}(0\leq j< m)$的值,一共有$m$个。
再枚举$a^{im}$,一共有$m$个,判断即可。
但是要求逆元$a^{-j}$,要求$gcd(a,n)=1$
我们现在来讨论$gcd(a,n)$不一定等于1的情况。
$$求最小的非负整数x满足,a^x \equiv b(mod n)$$
我们想通过消因子,使得变成上面那种情况。
设$d=gcd(a,n)$,且$a=a'd$,$n=n'd$
变成:
$(a'd)^x \equiv b(mod n'd)$
显然如果$b\%d\neq 0$,那么一定没有解
假设现在$b\%d=0$,$b=b'd$
变成:
$(a'd)^x\equiv b'd(mod n'd)$
$a'*(a'd)^{x-1} \equiv b'(mod n')$
$a'*a^{x-1} \equiv b'(mod n')$
很好,现在我们已经拿出来了一个因子$a'$了
但是我们还是不能保证$gcd(a,n')=1$,但我们可以做多次,使得$gcd(a,n')=1$
核心代码如下:
LL c=1,cnt=0; while(1) { LL d=gcd(a,n); if(d==1)break; if(b%d!=0)return 0; c*=a/d; cnt++; n/=d; b/=d; }
于是原问题变成:
$$求最小的非负整数x满足,c\times a^{x-cnt}\equiv b(mod n),其中gcd(a,n)=1$$
很好,变成上面那种情况了。
注意容易错的是,答案$x$有可能小于$cnt$,所以先要测试一下$0,1...,cnt-1$是否满足。