zoukankan      html  css  js  c++  java
  • 大步小步算法

    考虑这样一个问题:

    题目 给定正整数 (a,b,p) 求满足 (a^xequiv bpmod p) 的所有正整数解 (x),保证 (p) 是素数。

    分析 首先由费马小定理,(a^{p-1}equiv 1pmod p),也就是说暴力算法只需要枚举到 (p-1) 即可,我们考虑优化。

    我们考虑只暴力求解 (a^xmod p) 的前 (m) 个值,也即 (a^1mod p,a^2mod p,cdots,a^mmod p)。那么现在来考虑后面的数,将其 (m) 个一组分组(就是 (m+1,m+2,cdots,2m) 一组,(2m+1,2m+2,cdots,3m) 一组)。对于每一组这样考虑:如果

    [a^{km+t}equiv bpmod p ]

    这等价于

    [a^tequiv bcdot (a^{km})^{-1}equiv bcdot (a^{-m})^kpmod p ]

    也就是说,我们在枚举每一个 (k) 的时候可以直接将 (bcdot (a^{-m})^k mod p) 与每一个 (a^i) 对比,看是否有相同的,这可以用 (map) 实现。

    这个算法被称为大步小步(Baby Step Giant Step, BSGS, 拔山盖世)算法。它的复杂度为 (O((m+frac n m)log m)),当 (m=sqrt{n}) 时最优,为 (O(sqrt{n}log n))

    ll BSGS(ll a, ll b, ll mod)
    {
    	map<ll, ll> Map;
    	
    	ll m = sqrt(mod + 0.5), tmp = 1;
    	for(int i = 0; i < m; ++i) {
    		if(!Map.count(tmp)) Map[tmp] = i;
    		tmp = tmp * a % mod;
    	}
    	
    	ll inv = qPow(tmp, mod - 2, mod);
    	for(int i = 0; i < m; ++i) {
    		if(Map.count(b)) return i * m + Map[b];
    		b = b * inv % mod;
    	}
    	
    	return -1;
    }
    
  • 相关阅读:
    Linux6
    大小超过2t的分区规划 parted命令
    fdisk命令磁盘分区
    扩展
    磁盘管理
    在Linux中如何手动创建一个用户
    Linux5
    Linux4
    19_权限和分组
    18_django的用户模型和扩展django的用户模型
  • 原文地址:https://www.cnblogs.com/whx1003/p/12602150.html
Copyright © 2011-2022 走看看