首页 > 编程语言 >BSGS算法

BSGS算法

时间:2023-07-04 15:11:05浏览次数:48  
标签:ba pmod LL 算法 BSGS equiv

今天刚学了个算法:BSGS算法(Baby-Step Giant-Step),即大步小步算法。常用于求解离散对数问题。

该算法可以在 \(O(\sqrt p)\) 的时间内求解形如:\(a^{x}\equiv b\pmod{p}\) 的高次同余方程。

问题:

P3846 [TJOI2007] 可爱的质数/【模板】BSGS

给定整数 \(a,b,p\) 互质,求满足 \(a^{x}\equiv b\pmod{p}\) 的最小非负整数解 \(x\)。

思路:

由扩展欧拉定理:\(a^{x}\equiv a^{x\mod\varphi(p)}\pmod{p}\),

可知:\(a^{x}\) 在模 \(p\) 意义下的最小循环节为 \(\varphi\),

由欧拉函数定义可知,\(\varphi(p)<p\),因此 \(x\in[0,p]\),一定可以找到最小整数 \(x\)。

暴力:

暴力枚举 \(0\) ~ \(p\) 中 \(x\) 的取值,时间复杂度:\(O(p)\)

BSGS算法:

令 \(x=im-j\),其中 \(m=\lceil\sqrt p\rceil\),\(i\in[1,m]\),\(j\in[0,m-1]\)

当 \(i\) 取到最大值 \(m\),\(j\) 取到最小值 \(0\) 时,\(x\) 取到最大值 \(m\times m=p\)

当 \(i\) 取到最小值 \(1\),\(j\) 取到最大值 \(m-1\) 时,\(x\) 取到最小值 \(m-(m-1)=1\)

所以此时 \(x\in[1,p]\),而 \(x=0\) 的情况只用特判一下就行了。

则:$$a^{im-j}\equiv b\pmod p$$

\[\frac{a^im}{a^{j}}\equiv b\pmod p \]

\[a^{im}\equiv ba^{j}\pmod p \]

\[(a^{m})^{i}\equiv ba^{j}\pmod p \]

  1. 先枚举 \(j\),将 \((ba^{j},j)\) 扔进哈希表中,若 \(ba^{j}\) 出现过,则用更大的 \(j\) 来更换原来的 \(j\)。(因为要求最小的 \(x\),所以当 \(j\) 越大,\(x\) 就越小)

  2. 再枚举 \(i\),计算 \((a^{m})^{i}\),在哈希表中寻找相等的 \(ba^{j}\),找到第一个就输出,此时 \(x=im-j\) 最小。

由于 \(i\) 和 \(j\) 的枚举都只用枚举 \(\sqrt p\) 次,因此时间复杂度:\(O(\sqrt p)\).

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL BSGS(LL a,LL b,LL p){
    a%=p,b%=p;
    if(b==1)return 0;//特判x=0的情况
    LL m=ceil(sqrt(p)),t=b;
    unordered_map<int,int>Hash;//哈希表
    Hash[b]=0;
    for(int j=1;j<m;j++){
        t=t*a%p;//求b*a^j
        Hash[t]=j;
    }
    LL mi=1;
    for(int i=1;i<=m;i++)mi=mi*a%p;//求a^m
    t=1;
    for(int i=1;i<=m;i++){
        t=t*mi%p;//求(a^m)^i
        if(Hash.count(t))return i*m-Hash[t];
    }
    return -1;
}
int main(){
    LL a,b,p;scanf("%lld%lld%lld",&p,&a,&b);
    LL ans=BSGS(a,b,p);
    if(ans==-1)puts("no solution");
    else printf("%lld",ans);
    return 0;
}

标签:ba,pmod,LL,算法,BSGS,equiv
From: https://www.cnblogs.com/reclusive2007/p/17525808.html

相关文章

  • 算法竞赛中C++ vector的常规操作
    算法竞赛中C++vector的常规操作对vector的理解vector官方将其翻译为向量,但实际上是变长的动态数组,其可以存放各种类型的对象。vector定义语法大致格式:vector<类型>数组名在初始情况下,vector的大小是0,也就是空的数组。下面都以int型举例。vector<int>v;/......
  • 数据结构与算法coding过程中的记录
     1.init()时一定要记得malloc()申请新的内存空间(如果不申请内存空间程序返回的值是有内存里的脏数据,把人看得云里雾里找不到问题出在哪)2.带头结点单链表尾插法要注意:若LNode*p=L->next;循环条件是while(p!=NULL){p=p->next;},那么最后的p是NULL,此时在p(NULL)后插一个结点......
  • 《数据结构与算法》之图
    导言:图是数据结构教材上的最后一种数据结构了,它的使用范围最广,最多,也是最贴合我们实际生活的,图是一个多对多的数据结构,在前面的学习,了解到了一对一的数据结构----线性结构,以及一对多的结构----树形结构,现在要学的多对多的结构----图,图是对我们现实生活中很多实体的抽象,因为实际......
  • 详解共识算法的Raft算法模拟数
    摘要:Raft算法是一种分布式共识算法,用于解决分布式系统中的一致性问题。本文分享自华为云社区《共识算法之Raft算法模拟数》,作者:TiAmoZhang。01、Leader选举存在A、B、C三个成员组成的Raft集群,刚启动时,每个成员都处于Follower状态,其中,成员A心跳超时为110ms,成员B心跳超时为150m......
  • Bellman–Ford 算法
    目录Bellman-Ford算法记号过程举例应用应用1:Leetcode787.K站中转内最便宜的航班题目分析方法一:动态规划边界条件状态转移方法二:BellmanFord算法代码实现Bellman-Ford算法贝尔曼-福特(Bellman–Ford)算法是一种基于松弛(relax)操作的最短路径算法,可以求出有负权的图的最短路径......
  • Python递归算法从入门到精通
    递归是一种常见且重要的算法设计和解决问题的方法。它通过将问题分解为规模更小的子问题,并通过解决子问题来解决原始问题。递归算法的关键在于找到递归终止条件和递归调用的方式。本文将介绍递归的基本原理、应用场景,并通过相关的Python代码示例详细讲解递归算法的使用。一、递归......
  • Id 生成 - 雪花算法
    packagecom.changgou.entity.utils;importjava.lang.management.ManagementFactory;importjava.net.InetAddress;importjava.net.NetworkInterface;/***<p>名称:IdWorker.java</p>*<p>描述:分布式自增长ID</p>*<pre>*Twitter的......
  • 分布式id---雪花算法
    为什么要用分布式id随着业务的增长,后期可能会对数据库进行拆分的操作,通过数据库中间间链接。如果数据库表中的id采取的是自增策略,则会产生重复的id。使用分布式id便是为了避免此类现象。雪花算法snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使......
  • 数据结构与算法(一): 稀疏数组
    问题引入在五子棋游戏或类似的游戏中,我们可以把整个棋盘想象成是一个有规律的二维数组,其值由0、1、2三个数字组成,0代表空白区域,1代表白子,2代表黑子。这种情况:即当一个数组中大部分元素为0或者为同一值时,存储该数组数据可以使用稀疏数组来对原始数组进行精简,以减少原始数组中无用......
  • m基于MOEA算法的无线传感器网络最优部署matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:     2.算法涉及理论知识概要       无线传感器网络(WirelessSensorNetwork,WSN)是一种分布式传感器网络,由大量的无线传感器节点组成,它们可以自组织、自适应、自愈合,通过无线通信协同完成任务。WSN应用广泛,如环境监......