Baby Step Giant Step算法:求离散对数

本文章内容参考自这里

定义

BSGS算法中文名叫”大步小步算法”,用来求解如下同余方程x的最小正整数解:

axb(modp)(0<=x<p) a x ≡ b ( m o d p ) ( 0 <= x < p )

//这里p为素数, a、b、p已知,且0<=a,b< p(如果a,b大于p,可将他们对p取模)。
//显然若a为p的一个原根,则x即为b关于a的离散对数(mod p),故此算法可求离散对数。

算法原理

将x重写为 x=im+j x = i ∗ m + j
其中 m=p,i=x/m,j=x%m. m = ⌈ p ⌉ , i = x / m , j = x % m .
显然 0i<m,0j<m. 0 ≤ i < m , 0 ≤ j < m .
那么我们就可以分别枚举i和j,以找到符合条件的x。
这里采用的方法是,先枚举j,将其所有的结果放入一个哈希表中,然后再枚举i,看能不能找到一个满足条件的j。

算法复杂度分析

这种做法毋庸置疑,肯定是对的。但我们得思考为什么这样做。
我们可以结合幂的性质来思考, ax+y=axay a x + y = a x ∗ a y ,幂的和的关系会转换成值的积,而积我们往往只会枚举sqrt(p),所以我们可以使j< sqrt(p),再使前面由 pi ⌈ p ⌉ ∗ i ,从而减少复杂度。所以这样做的关键在于幂的和可以变成两个数的乘积(思想很重要)。

步骤

1.令 m=p m = ⌈ p ⌉
2.枚举j,j的范围是[0,…,m)。
ajmodp a j mod p 作为键存入hash表,其值为j。
3.枚举i,i的范围是[0,…m)。
A=(am)i A = ( a m ) i 是已知(代入i),设未知数j,满足 A(aj)B(modp) A ∗ ( a j ) ≡ B ( mod p ) ,那么j即为第二步枚举的j,而 aj a j 即为第二步放入hash表内的值,由扩展欧几里得可求出 aj a j 的值。在hash表里找 aj a j 的值,如果找到了则记录j的值,跳出此循环。
4.最后的结果即为 im+j i ∗ m + j

实现

/*==================================================*\
| Baby-Step-Giant-Step 大步小步算法
| 求 a^x === b (mod p) 中的 x值 -- 此处p仅为素数
| 实际运用中用自己的hash表代替map可防TLE
\*==================================================*/
LL BSGS(LL a, LL b, LL p) {
    a %= p; b %= p;
    map<LL, LL> h;
    LL m = ceil(sqrt(p)), x, y, d, t = 1, v = 1;
    for(LL i = 0; i < m; ++i) {
        if(h.count(t)) h[t] = min(h[t], i);
        else h[t] = i;
        t = (t*a) % p;
    }
    for(LL i = 0; i < m; ++i) {
        d = extgcd(v, p, x, y);
        x = (x* b/d % p + p) % (p);
        if(h.count(x)) return i*m + h[x];
        v = (v*t) % p;
    }
    return -1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值