BSGS算法

BSGS算法介绍

BSGS是用来解决形如 yx ≡ z mod p 的问题的,它能够在有解的情况下求出来最小值。这里前提是gcd(y, p) == 1,否则就需要exBSGS解决。

算法过程

首先我们让 x = i*m-k
 这样上面的式子就变为了 yi*m/yk ≡ z mod p, 通过变换得到 yi*m ≡ z * yk mod p。其中m等于ceil(sqrt( p)),也就是向上取整根号p,k的范围是0~m-1。
 通过枚举得到所有yk k∈ [0, m),并使用hash表或者map存储当前k值,然后在枚举左边的i,如果在hash表或者map里面能够找到,就代表找到了最小的解。输出i * m-map[num]就行了。
 
 1,首先说为什么m等于ceil(sqrt§)呢?
 没有为啥,m等于什么都行,但是当他等于ceil(sqrt§)时是最快的。
 
 2,i的取值范围为什么是[1, m]?
 首先需要保证x为正数,所以i一定大于0。然后通过欧拉定理的应用我们知道 at mod φ( p) = at mod p, 这样就保证了x一定是小于p的,因为p为素数的时候欧拉函数值最大为p-1。所以i * m-k <= p,而k的取值范围为k∈ [0, m),当k = 0的时候,i * m <= p, 又因为我们知道m取值为sqrt( p ), 所以i的取值范围是[1, m]。
 
 3,为什么得到的一定是最小解?
 这个算法叫做大小步算法,在记录所有yk k∈[0, m)的时候就是小步走,小步走时,如果遇到取模后相同的值就会用当前的k值替换到hash表里面的,这样最后找到的一定是最大的k,因此 i * m - k一定是最小值也就是最小解。

代码实现

// y^x = z mod p
void slove(ll y, ll z, ll p)
{
    map<ll, int> s;
	//特判一下,如果y是p的倍数一定无解
    if (y%p == 0)
    {
        printf("Orz, I cannot find x!\n");
        return;
    }

    y%=p, z%=p;
	//特判
    if (z == 1)
    {
        printf("0\n");
    }
    else
    {	//求出来m的值,加一效果同ceil一样
        int m = sqrt(p)+1;
        ll t = z;
		//求解y^k,并记录下来,k是从[0, m)的,
		//这里为了让最后一个t值也记录下来,就循环到了m
        for (int i=0; i<=m; i++)
        {
            s[t] = i+1; //记录位置加一,一会在加上来,因为判断需要用到值,没办法从0开始
            t = t*y%p;
        }

        ll q = qul(y, m, p);
        t = 1;
        bool flag = false;

        for (int i=1; i<=m; i++)
        {
            t = t*q%p;

            if (s[t])
            {
                printf("%d\n", i*m-s[t]+1);
                flag = true;
                break;
            }
        }

        if (!flag)
                printf("Orz, I cannot find x!\n");
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值