bsgs algorithm

ax≡b(mod n)

大步小步算法,这个算法有一定的局限性,只有当gcd(a,m)=1时才可以用

原理

此处讨论n为素数的时候。

ax≡b(mod n)(n为素数)

由费马小定理可知,只需要验证0,1,2...n-1是不是解即可,因为an-1 = 1mod(n)

算法过程

1、首先求出a0,a1,a2,...,am-1 模上n的值是否为b,存储在e[i]中,求出am的逆a-m

2、下面考虑am,am+1,...,a2m-1 模上n的值是否为b

此时不用一一检查,如果当中有解,相当于存在e[i],使得e[i] * am = b mod(n)

两边乘上a-m,e[i] = b * a-m mod(n),只需要检查存不存在这样的e[i]即可

3、同理,可以递推检查出a2m - a3m-1中解的情况

为了方便,把e[i]存储在map<int, int>x中,x[j]表示满足ei =j 的最小下标(因为可能有多个值相同)

 map<ll, int>x;
ll log_mod(ll a, ll b, ll n)//n为素数
{
//if(b >= n)return -1;
a %= n;b %= n;//注意题目,如果b >= n是不存在解的
if(a == )
{
if(b == )return ;if(b == 1)return 0;
else return -;
}
ll m = ceil(sqrt(n + 0.5));
ll v = pow(a, n - - m, n);
x.clear();
x[] = m;
ll e = ;
for(int i = ; i < m; i++)//计算a的i次方mod n,并存下来
{
e = e * a % n;
if(!x[e])x[e] = i;
}
for(int i = ; i < m; i++)//计算a^(im), a^(im+1),...,a^(im+m-1)
{
int num = x[b];
if(num)return i * m + (num == m ? : num);
b = b * v % n;
}
return -;
}

扩展:

当n不为素数的时候,如何求解ax≡b(mod n) ?

转化成gcd(a, n) = 1即可

如何转化呢?

利用公式:ax≡b(mod n)⇔ax/d ≡ b/d (mod n/d),d=gcd(a,n)(这里是a乘上x,上述求解方程为ax

每次用一个a和m和b消去gcd(a, n),消δ次,每次n /= g, b /= g,迭代更新下一个g,直到g=1

最后ax变成了ax - δ *a', 方程变成:ax - δ *a' = b' (mod n')     这里a' b' n'都是消因子之后的值

满足:a' * g = aδ  b' * g = b  n' * g = n    g = gcd(aδ, n)

如果某一步g不整除b',直接返回-1

如果某一步b' = a',假设此时消因子次数达到cnt次,那就返回cnt

  因为消因子次数cnt次等价于

  原方程:ax-cntacnt = b (mod n)

  消因子后:ax-cnta' = b' (mod n')

  若此时b' = a' 那么等式就可以直接消去a' b',得到:ax-cnt = 1 (mod n),解就是cnt

下面求解:ax - δ *a' = b' (mod n')  

可以求出a'的逆元,然后乘过去,用上述的大步小步算法求解

下面介绍一个技巧不用求逆元。

先把上述式子写成ax * tmp = b (mod n)   求出x之后加上δ就是解。

设m = sqrt(n +0.5), x = k * m - q (1 <= k <= m, q <= m)

上式可写成tmp * a k*m-q = b (mod n)

等价于  tmp * a k*m = b * aq(mod n)

可以从1-m枚举k,每次求出tmp * a k*m 判断是不是存在b*aq

最开始的大步小步算法也可以这样写

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll pow(ll a, ll b, ll m)
{
ll ans = ;
a %= m;
while(b)
{
if(b & )ans = (ans % m) * (a % m) % m;
b /= ;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll ext_log_mod(ll a, ll b, ll n)
{
if(b >= n)return -;//一些特殊情况的判断
a %= n;
if(b == )return ;
//if(n == 1)return -1;
ll cnt = ;//记录消因子次数
ll tmp = ;//存当前a'的值
for(ll g = __gcd(a, n); g != ; g = __gcd(a, n))
{
if(b % g)return -;//不能整除
b /= g; n /= g; tmp = tmp * a / g % n;
cnt++;
if(b == tmp)return cnt;
} ll m = sqrt(n + 0.5);
ll t = b;
map<ll, ll>Map;//记录b * a ^ i, i
Map[b] = ;
for(int i = ; i <= m; i++)
{
b = b * a % n;
Map[b] = i;
}
a = pow(a, m, n);
for(int k = ; k <= m; k++)//枚举k
{
tmp = tmp * a % n;//求出tmp*a^(k*m)
if(Map.count(tmp))return k * m - Map[tmp] + cnt;
}
return -;
}
int main()
{
ll a, b, p;
while(scanf("%lld%lld%lld", &a, &p, &b) != EOF)
{
ll ans = ext_log_mod(a, b, p);
if(ans == -)printf("Orz,I can’t find D!\n");
else printf("%lld\n", ans);
}
return ;
}

离散对数&&大步小步算法及扩展的更多相关文章

  1. 【题解】Matrix BZOJ 4128 矩阵求逆 离散对数 大步小步算法

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4128 大水题一道 使用大步小步算法,把数字的运算换成矩阵的运算就好了 矩阵求逆?这么基础的线 ...

  2. UVA 11916 Emoogle Grid 离散对数 大步小步算法

    LRJ白书上的题 #include <stdio.h> #include <iostream> #include <vector> #include <mat ...

  3. 离散对数及其拓展 大步小步算法 BSGS

    离散对数及其拓展 离散对数是在群Zp∗Z_{p}^{*}Zp∗​而言的,其中ppp是素数.即在在群Zp∗Z_{p}^{*}Zp∗​内,aaa是生成元,求关于xxx的方程ax=ba^x=bax=b的解, ...

  4. [模板]大步小步算法——BSGS算法

    大步小步算法用于解决:已知A, B, C,求X使得 A^x = B (mod C) 成立. 我们令x = im - j | m = ceil(sqrt(C)), i = [1, m], j = [0, ...

  5. 大步小步算法模板题, poj2417

    大步小步模板 (hash稍微有一点麻烦, poj不支持C++11略坑) #include <iostream> #include <vector> #include <c ...

  6. 洛谷 - P4861 - 按钮 - 扩展大步小步算法

    https://www.luogu.org/problemnew/show/P4861 把好像把一开始b==1的特判去掉就可以AC了. #include<bits/stdc++.h> us ...

  7. BSGS-Junior·大步小步算法

    本文原载于:http://www.orchidany.cf/2019/02/06/BSGS-junior/#more \(\rm{0x01}\) \(\mathcal{Preface}\) \(\rm ...

  8. [BSGS]大步小步算法

    问题 BSGS被用于求解离散对数,即同余方程: \[ A^x\equiv B\pmod{P} \] 求\(x\)的最小非负整数解. 保证\(A\perp P\)(互质). 分析 首先,我们根据费马小定 ...

  9. BSGS算法(大步小步算法)

    计算\(y^x ≡ z \ mod\ p\) 中 \(x\) 的解. 这个模板是最小化了\(x\) , 无解输出\(No \ Solution!\) map<ll,ll>data; ll ...

随机推荐

  1. 很实用的web性能测试插件:Yslow , PageSpeed

    package org.springframework.web.servlet.resource; import java.io.IOException; import java.io.Unsuppo ...

  2. VS中特殊的注释——TODO/UNDONE/HACK的使用

    在代码的后面添加形如下面注释: //TODO: (未实现)…… //UNDONE:(没有做完)…… //HACK:(修改)…… 等到再次打开VS的时候,找到 :视图>任务列表 即可显示所有带有T ...

  3. 【转】如何用Maven创建web项目(具体步骤)

    使用eclipse插件创建一个web project 首先创建一个Maven的Project如下图 我们勾选上Create a simple project (不使用骨架) 这里的Packing 选择 ...

  4. JSONObject与null

    前言 今天在写代码的时候发现在 JSON 中 由于put了key对应的value为null,结果这个JSON键值对没有输出 org.json.JSONObject 在orgJSON 中,如果直接put ...

  5. eclipse的debug技巧之一

    如下图,断点设置的地方会在i==0时就停住,假如我们想在i等于某个值的时候才停住,那么可以添加“过滤条件” 具体操作是在debug模式下,右键breakpoints标签下我们所设置的断点,点击右键菜单 ...

  6. 局域网内使用ipv6 通信

    链路本地地址:用于网段内通信,不能跨路由访问 在ping本地链路地址和全球唯一地址时有点差别,链路本地地址需要加上网络接口号 Linux 查看ipv6链路本地地址:ifconfig linux系统pi ...

  7. js比较好的一些方法

    js里面有些方法比较容易忘记,但却很实用,很好用的一些方法.在此记录: 1.Math.ceil(x) — 返回大于等于数字参数的最小整数(取整函数),对数字进行上舍入 2.Math.floor(x)– ...

  8. java多线程中的死锁、活锁、饥饿、无锁都是什么鬼?

    死锁.活锁.饥饿是关于多线程是否活跃出现的运行阻塞障碍问题,如果线程出现了这三种情况,即线程不再活跃,不能再正常地执行下去了. 死锁 死锁是多线程中最差的一种情况,多个线程相互占用对方的资源的锁,而又 ...

  9. Android图片处理--缩放

    PS:在开发中我们会遇到一些图片处理问题,比如说缓存图片了.限制图片大小了.查看图片了等.上一篇文章介绍了图片的全景效果查看,今天介绍一个图片缩放,我们如果有时间的话,可以自己写一个属于自己的库,里面 ...

  10. centos虚拟机下安装nginx

    通过yum安装 yum install epel-release -y(企业级的镜像源) yum install nginx-y 启动.停止.重启 service nginx start servic ...