【离散对数 && EXBSGS】Gym - 101853G Hard Equation

Step1 Problem:

a^x ≡ b(mod m).
给你 a, b, m, 求 x.
数据范围:
1<=T<=500, 0 <= a, b < m <= 1e9.

Step2 Ideas:

学习算法博客
说说自己的理解:
a^x ≡ b(mod m).

a 和 m 互质:
根据欧拉定理:如果 gcd(a, m) == 1, a^phi(m) ≡ 1(mod m).
所以 a 和 m 互质,a^x mod m 隔 phi(m) 次一定存在周期。
a^x ≡ b(mod m).
x = b * s + r:需要用逆元
由于 phi(m) < m, 所以我们令 s = sqrt(m), 枚举 x = [0, s) 求出 a^x 用 map 存起来。
当 xi = [i * s+1, (i+1) * s) 时:xi = i * s + x, a^xi ≡ b(mod m) -> a^x ≡ b * a^(-i * s)(mod m).
此时:用 map 判断 b * a^(-i * s) 是否存在,如果存在则有解。
直到 xb = [b * s+1, (b+1) * s) 为止。
x = b * s - r:不需要用逆元
由于代码采用是不用逆元的方法,所以直接看代码即可。

a 和 m 不互质:
我们需要把方程转换成,a 和 m 互质。
a^x ≡ b mod m -> a^x + y*m = b.
由裴蜀定理,g = gcd(a, m) 不整除 b 那么无解返回 -1.
否则:a/g * a^(x-1) + m/g * y = b/g.
模方程:a/g * a^(x-1) ≡ b/g (mod m/g).
令 m1 = m/g, b1 = b/g * (a/g)^(-1),得到新方程
a^x1 ≡ b1(mod m1).
可知:x = x1+1.
由于 a 是不变的,不断重复上述操作,直到 a 和 m1 互质
如果 b1 = 1, 此时存在解 x1 = 0. 在求出 x 即可

Step3 Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll log_ab(ll a, ll b, ll MOD)
{
    a = a%MOD; b = b%MOD;
    if(b == 1) return 0;
    int cnt = 0;
    ll t = 1;
    for(ll g = __gcd(a, MOD); g != 1; g = __gcd(a, MOD))
    {
        if(b%g) return -1;//由裴蜀定理,可知无解
        MOD /= g, b /= g;
        t = t * a / g % MOD;
        cnt++;//记录 x -> x1 经过了几次。
        if(t == b) return cnt;//b1 = 1.
    }

    unordered_map<ll, ll> mp;
    int m = ceil(sqrt(1.0 * MOD));
    ll e = 1;
    for(int i = 0; i < m; i++) {//将 a^i 存起来,i = [0, sqrt(m)),如果不用逆元需要将 b*a^i 存起来。
       mp[e*b%MOD] = i;
       e = e * a % MOD;
    }
    // e  = a^(sqrt(m))
    ll nw = t;
    for(int i = 1; i <= m + 1; i++) {
        nw = e * nw % MOD;
        if(mp.count(nw)) {
            return i * m - mp[nw] + cnt;
        }
    }
    return -1;
}
int main()
{
    int T, a, b, m;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d %d", &a, &b, &m);
        ll x = log_ab(a, b, m);
        if(x == -1) ;
        else printf("%lld\n", x);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值