$BSGS$ 算法 $Baby Steps Giant Steps$.
致力于解决给定两个互质的数 $a, p$ 求一个最小的非负整数 $x$ 使得 $a^xequiv b(mod p)$ 其中 $b$ 为任意正整数,$2≤a<p$,$2≤b<p$
该算法使用的原理与欧拉定理有关,其中$a, p$互质
$a^{phi (p)}equiv 1(mod p)$
又因为
$a^0equiv 1(mod p)$
所以$0到phi p$是一个循环节,也就是说该算法最多查找$phi (p)$次就可以找到答案,否则就无解。
设$x=im-k$其中$0≤k≤m$ 原式变为
$a^{im-k}equiv b(mod p)$
两边乘以$a^k$得到
$a^{im}equiv a^kb(mod p)$
然后我们可以拆成左右两部分分别进行枚举$i$和$k$。
①先枚举$k$,把对应的结果$a^kb$和对应的$k$放入$map$中,$map\_name[a^kb]=k$。$(k from 0 to m)$
②然后枚举$i$,把得到的结果$a^{im}$在$map$中进行查找,如果$map\_name.count(a^{im})$可以找到,则输出此时的$im-k$即可。($i from 1 to m$)
如果超出查找范围还没找到,则无解。
这里注意下,对$a^{im}$枚举时,要先快速幂预处理出来$a^m$,然后枚举$i$即可。
算法时间复杂度为$O(max(m, phi (p)/m))$.
最坏情况为$p$为质数$phi (p)=p-1$
此时将$m$取$sqrt p$为最小,时间复杂度为$O(sqrt p)$。
$m$取$sqrt p+1$或$ceil(sqrt p)$。
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n, p, b; unordered_map<ll, int> vis; inline ll fp( ll a, ll b ){ a %= p; ll res = 1; while( b ){ if( b&1 ) res = res*a%p; b >>= 1; a = a*a%p; } return res; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> p >> b >> n; ll m = ceil(sqrt(p)); /*算法复杂度O( max(m, phi(p)/m) ) 所以m取ceil(sqrt(p))最快O(sqrt(p)) */ ll tmp = n; for( int k=0; k<=m; k++,(tmp*=b)%=p ){ vis[tmp] = k; } ll t = fp(b, m); tmp = t; bool flag = 0; for( int i=1; i<=m; i++, tmp=tmp*t%p ){ if( vis.count(tmp) ){ flag = 1; cout << i*m-vis[tmp] << endl; break; } } if(!flag) cout << "no solution" <<endl; return 0; }