#include <bits/stdc++.h>
#include <tr1/unordered_map>
using namespace std;
using std::tr1::unordered_map;
#define ll long long
const int maxn=1e6+7;
const int mod=998244353;
const int INF=0x3f3f3f3f;
/*
BSGS算法 b^l==n%p 求解最小的l
不妨直接把l拆分成i*m-j,这样的话同余方程就变为b^(i*m)==n*b^j%p
直接枚举j属于[0,m) m=ceil///向上取整(sqrt(p)) map记录当前的j的数值
随后枚举i属于[0,m)查询map是否存在j满足且需要满足i*m>j=op[s]
很显然这只是gcd(b,p)=1的情况,此时枚举只到了m-2与费马小定理对应
EXBSGS 由于gcd(p,b)不一定为1,所以我们可以求出gcd(p,b)根据裴蜀定理,有解的条件gcd(p,b)|n
所以就一直求出gcd(d2=(p/d),b),一直到他们之间互质,期间如果gcd(p/d,b)!|n就是无解
最后可以得到b^cnt/(d1*d2......*dcnt) *b^(l-cnt) == n/(d1*d2......*dcnt)mod(p/(d1*d2......*dcnt))
(d1*d2......*dcnt)=D
b^cnt/D * (b^(l-cnt))===n/Dmod(p/D)
b^cnt/D和n/d互质所以一定有解,所以将原来的S=1ll改为b^cnt/D直接用BSGS求(b^(l-cnt))
求得的x是l-cnt最后要加上cnt
*/
unordered_map<ll,ll>op;
ll p,b,n;
ll quick_pow(ll a,ll b,ll p)
{
ll ans=1;
while (b)
{
if (b&1)///b为奇数
ans=(ans*a)%p;
a=(a*a)%p;///b为偶数
b>>=1;
}
return ans;
}
ll BSGS(ll p,ll b,ll n,ll ans)
{
op.clear();
ll m=ceil(sqrt(p));
ll s=0;
for (ll i=0,s=n;i<m;++i,s=s*1ll*b%p)///枚举的时候map记录位置
{
op[s]=i;
}
for (ll i=0,tmp=quick_pow(b,m,p),s=ans;i<m;++i,s=s*1ll*tmp%p )///查找j
{
if (op.find(s)!=op.end())
{
if (i*m>=op[s])return 1ll*i*m-op[s];
}
}
return -1ll;
}
ll GCD(ll a,ll b){return b?GCD(b,a%b):a;}
ll EXBSGS(ll p,ll b,ll n)
{
b%=p;
n%=p;///先取模一下保证n,b<p
if (n==1||p==1)return 0;///n==1 l==0 p==1 n%1==0 l任意取值,但要最小所以为0
ll cnt=0;
ll d=0;
ll ans=1ll;
while (d!=1)
{
d=GCD(b,p);
if (n%d==1)return -1ll;///同余方程无解
++cnt;
p/=d;
n/=d;
ans=(ans*1ll*b/d)%p;
if (ans==n)return cnt;///特判情况 n*b^(l-cnt)==n/D mod(p/D) 此时的n*D==n%(p/d) 所以l==cnt
}
ll ret=BSGS(p,b,n,ans);
if (ret==-1ll)return -1ll;
else return ret+cnt;///求的是a^(x-cnt)
}
int main()
{
while (EOF!=scanf("%lld%lld%lld",&b,&p,&n))///b^l==n%p
{
if (!b&&!p&&!n)return 0;
ll cnt=EXBSGS(p,b,n);
cnt==-1ll?cout<<"No Solution"<<endl:cout<<cnt<<endl;
}
return 0;
}
摘录自对该博客的理解