版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
当时,我们就不能用BSGS算法求解。既然不互质时,我们无法求解,那我们就想办法让
如果, 就成了我们熟悉的BSGS算法了。
如果,
如果,则方程无解
否者一直除到互质为止
假设进行了t次除法,
#include<bits/stdc++.h>
using namespace std;
const int MOD = 76543;
typedef long long ll;
ll hs[MOD], id[MOD], _next[MOD], head[MOD], top;
// hs hash表 记录存的值
// id 值所所对应的id
// _next 相同hash值的上一个序号
// head hash 值相同的最后一个元素的序号
// 其实就是用链式前向星实现的hash表
ll gcd(ll a, ll b) //最大公约数
{
if(b == 0) return a;
while(b) {
ll t = a;
a = b;
b = t % b;
}
return a;
}
ll exgcd(ll a, ll b, ll &x, ll &y) // 扩展欧几里得
{
if(b == 0) {
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y);
ll t = x;
x = y;
y = t - a / b * y;
return d;
}
ll inv(ll a, ll p) // 求解逆元
{
ll x, y;
exgcd(a, p, x, y);
return (x % p + p) % p; // 不能直接 return x, 因为 x 可能为负数
}
void insert(ll x, ll y) // 插入hash表
{
ll k = x % MOD;
hs[top] = x;
id[top] = y;
_next[top] = head[k];
head[k] = top ++;
return ;
}
ll find(ll x) // 查找
{
ll k = x % MOD;
for(ll i = head[k]; i != -1; i = _next[i]) if(hs[i] == x) return id[i];
return -1;
}
ll EXBSGS(ll a, ll b, ll n) // 扩展大步小步算法, gcd(a, n) != 1
{
memset(head, -1, sizeof(head)); // hash表初始化
top = 1;
if(b == 1 ) return 0; // a ^ 0 = 1 mod n
ll cnt = 0, tmp = 1, d;
while((d = gcd(a, n)) != 1) { // a, n 不互质
if(b % d != 0) return -1; // 无解
b /= d;
n /= d;
tmp = tmp * (a / d) % n;
cnt ++;
if(b == tmp) return cnt; // a^{x - cnt} = 1 mod n
}
b = b * inv(tmp, n) % n;
ll m = sqrt(n * 1.0), j;
ll x = 1, p = 1;
for(ll i = 0; i < m; i++, p = p * a % n) insert(b * p % n, i); // 枚举 右边 1 ~ sqrt(n)
for(ll i = m; ; i += m) { // 枚举左边sqrt(n) * {1 ~ sqrt(n)}
if((j = find( x = x * p % n)) != -1) return i - j + cnt;
if(i > n) break;
}
return -1;
}
int main()
{
ll a, b, n;
while(scanf("%lld %lld %lld", &a, &n, &b) == 3 && (a || n || b)) {
ll ans = EXBSGS(a, b, n);
if(ans == -1) printf("No Solution\n");
else printf("%lld\n", ans);
}
return 0;
}