【数论】同余(六):高次同余方程:BSGS算法

同余问题共7part,我的博客链接:

高次同余方程

只考虑: a x ≡ b ( m o d    m ) a^x\equiv b(\mod m) axb(modm)

为保持统一,放一下手写的哈希(来自kuangbin的模板)

// (x,y)的HASH
#define MOD 76543
int hs[MOD], head[MOD], nxt[MOD], id[MOD], top;
void insert(int x, int y)
{
    int k = x % MOD;
    hs[top] = x, id[top] = y, nxt[top] = head[k], head[k] = top++;
}
int find(int x)
{
    int k = x % MOD;
    for (int i = head[k]; i != -1; i = nxt[i])
        if (hs[i] == x)
            return id[i];
    return -1;
}

BSGS算法

gcd ⁡ ( a , m ) = 1 \gcd(a,m)=1 gcd(a,m)=1 ,令 x = k s − t , s = ⌈ m ⌉ , 0 ≤ t < s , 0 < k ≤ s + 1 x=ks-t,s=\lceil \sqrt m\rceil,0\leq t<s,0<k\leq s+1 x=kst,s=m ,0t<s,0<ks+1 s s s 的取值有严格证明这样复杂度最低),则原式变为 a k s ≡ b a t ( m o d    m ) a^{ks}\equiv ba^{t}(\mod m) aksbat(modm) ,枚举可能的 t t t ,存下 b a t ba^t bat 的哈希值,再枚举左边的 k k k a k s a^{ks} aks 查表。

// 普通BSGS: a^x==b mod m, gcd(a,m)=1
int BSGS(int a, int b, int m)
{
    if(b == 1 || m == 1) // 注意这里的特判
        return 0;
    int s = sqrt(m) + 1;
    memset(head,-1,sizeof(head));
    top=0;
    for (int i = 0, tmp = b; i < s; i++, tmp = tmp * a % m)
        insert(tmp, i);
    int as = qpow(a, s, m); // 快速幂算a^s
    for (int i = 1, tmp = as; i <= s + 1; i++, tmp = tmp * as % m)
    {
        int qry = find(tmp);
        if (qry == -1)
            continue;
        return i * s - qry;
    }
    return -1;
}

扩展BSGS算法

gcd ⁡ ( a , m ) = d ≠ 1 \gcd(a,m)=d\neq 1 gcd(a,m)=d=1 ,等价变换为 a x + m y = b a^x+my=b ax+my=b 有解的条件是 d ∣ b d\mid b db 。两边同除 d d d ,则变为 a d a x − 1 + y m d = b d \frac{a}{d}a^{x-1}+y\frac{m}{d}=\frac{b}{d} daax1+ydm=db 不断检查 gcd ⁡ ( b d , a ) \gcd(\frac{b}{d},a) gcd(db,a) 并除掉,直到为 1 1 1
记每次除的数乘积为 D D D ,则原式变为 a k D a x − k + y m D = b D \frac{a^k}{D}a^{x-k}+y\frac{m}{D}=\frac{b}{D} Dakaxk+yDm=Db a x − k ≡ b D D a k ( m o d    m D ) a^{x-k}\equiv \frac{b}{D}\frac{D}{a^k}(\mod \frac{m}{D}) axkDbakD(modDm) 用BSGS求解即可。

int exBSGS(int a, int b, int m)
{
    if (b == 1 || m == 1)
        return 0;
    int k = 0, atmp = 1;
    while (1)
    {
        int tmp = __gcd(m, a);
        if (tmp == 1)
            break;
        if(b % tmp)
            return -1;
        b /= tmp, m /= tmp, k++;
        atmp = atmp * (a / tmp) % m;
        if (b == atmp)
            return k;
    }
    return BSGS(a, b * inv(atmp, m) % m, m) + k;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值