BSGS算法解析
前置芝士:
1.快速幂(用于求一个数的幂次方)
2.STL里的map(快速查找)
详解
BSGS 算法适用于解决高次同余方程 \(a^x\equiv b (mod p)\)
由费马小定理可得 x <= p-1
我们设 \(m = sqrt(p)\) 至于为什么写,下文会讲到。
那么\(x\)就可以用 \(m\) 表示出来。
即 x = \(k \times m - j\)
移项可得 \(a^t \equiv b\times a^j\) 其中 t = \(k \times m\)
这也就是我们为什么把\(x\)用 \(k \times m - j\)来表示。
因为改为加\(j\)后,移项后要求逆元,就会变得很麻烦。
这样,我们就可以枚举每个\(k\)和\(j\),来判断左右两边得值是否相等就行了。
首先,我们可以枚举j 将 \(b\times a^j\)放入map中。
然后,从小到大枚举\(k\),在哈希表中,找到最大的\(j\)满足 \(a^t \equiv b\times a^j\) 其中 t = \(k \times m\)
若存在\(k\times m -j\)就是方程的解
关于上文中,为什么要设\(m = sqrt(p)\)
是为了保证BSGS的复杂度,是左右两边的数尽可能的均匀。
例题
模板题,水过去了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define LL long long
int a,b,p;
LL ksm(LL a, LL b)
{
LL res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % p;
a = a * a % p;
}
return res;
}
int BSGS(int a,int b,int p)
{
map<LL,int> hash; hash.clear();
int m = (int)sqrt(p);
for(int i = 0; i <= m; i++)
{
LL val = ksm(a,i) * b % p;//b * a ^ i
hash[val] = i;//放入map中
}
a = ksm(a,m);//a ^ m
for(int i = 0; i <= m; i++)
{
LL val = ksm(a,i);//(a^m)^i
int j = hash.find(val) == hash.end() ? -1 : hash[val];//如果没有j就为-1
if(j >= 0 && i * m - j >= 0) return i * m - j;//找到一组解
}
return -1;
}
int main()
{
scanf("%d%d%d",&p,&a,&b);
LL ans = BSGS(a,b,p);
if(ans == -1) cout<<"no solution"<<endl;
else printf("%lld\n",ans);
return 0;
}
一道很多算法综合在一起的模板题,水过去了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
#define LL long long
int t,opt,a,b,p,x,y;
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
return s * w;
}
LL gcd(LL a, LL b)
{
if(b == 0) return a;
else return gcd(b,a%b);
}
LL ksm(LL a, LL b)//快速幂
{
LL res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % p;
a = a * a % p;
}
return res;
}
LL exgcd(int a,int b, int &x,int &y)//扩展欧几里得
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
LL gcd = exgcd(b,a%b,y,x);
y -= a / b * x;
return gcd;
}
LL BSGS(LL a,LL b,LL p)//BSGS
{
map<LL,int> hash; hash.clear();
int m = (int) sqrt(p);
b % p;
for(int i = 0; i <= m; i++)
{
LL tmp = ksm(a,i) * b % p;
hash[tmp] = i;
}
a = ksm(a,m);
if(a == 0) return b == 0 ? 1 : -1;//特判当a为0的情况
for(int i = 0; i <= m; i++)
{
LL tmp = ksm(a,i);
int j = hash.find(tmp) == hash.end() ? -1 : hash[tmp];
if(j >= 0 && i * m - j >= 0) return i * m - j;
}
return -1;
}
int main()
{
t = read(); opt = read();
while(t--)
{
a = read(); b = read(); p = read();
if(opt == 1)
{
LL ans = ksm(a,b);
printf("%lld\n",ans);
}
if(opt == 2)
{
LL k = exgcd(a,p,x,y);
if(b % k) cout<<"Orz, I cannot find x!"<<endl;
else printf("%lld\n",(x * (b/k) % p + p)%p);
}
if(opt == 3)
{
LL ans = BSGS(a,b,p);
if(ans == -1) cout<<"Orz, I cannot find x!"<<endl;//无解情况
else printf("%lld\n",ans);
}
}
return 0;
}
ENDING
BSGS算法解析的更多相关文章
- 【codevs 1565】【SDOI 2011】计算器 快速幂+拓展欧几里得+BSGS算法
BSGS算法是meet in the middle思想的一种应用,参考Yveh的博客我学会了BSGS的模版和hash表模板,,, 现在才会hash是不是太弱了,,, #include<cmath ...
- 地理围栏算法解析(Geo-fencing)
地理围栏算法解析 http://www.cnblogs.com/LBSer/p/4471742.html 地理围栏(Geo-fencing)是LBS的一种应用,就是用一个虚拟的栅栏围出一个虚拟地理边界 ...
- KMP串匹配算法解析与优化
朴素串匹配算法说明 串匹配算法最常用的情形是从一篇文档中查找指定文本.需要查找的文本叫做模式串,需要从中查找模式串的串暂且叫做查找串吧. 为了更好理解KMP算法,我们先这样看待一下朴素匹配算法吧.朴素 ...
- bzoj2242: [SDOI2011]计算器 && BSGS 算法
BSGS算法 给定y.z.p,计算满足yx mod p=z的最小非负整数x.p为质数(没法写数学公式,以下内容用心去感受吧) 设 x = i*m + j. 则 y^(j)≡z∗y^(-i*m)) (m ...
- Peterson算法与Dekker算法解析
进来Bear正在学习巩固并行的基础知识,所以写下这篇基础的有关并行算法的文章. 在讲述两个算法之前,需要明确一些概念性的问题, Race Condition(竞争条件),Situations lik ...
- [BSGS算法]纯水斐波那契数列
学弟在OJ上加了道"非水斐波那契数列",求斐波那契第n项对1,000,000,007取模的值,n<=10^15,随便水过后我决定加一道升级版,说是升级版,其实也没什么变化,只 ...
- python常见排序算法解析
python——常见排序算法解析 算法是程序员的灵魂. 下面的博文是我整理的感觉还不错的算法实现 原理的理解是最重要的,我会常回来看看,并坚持每天刷leetcode 本篇主要实现九(八)大排序算法 ...
- BSGS算法
BSGS算法 我是看着\(ppl\)的博客学的,您可以先访问\(ppl\)的博客 Part1 BSGS算法 求解关于\(x\)的方程 \[y^x=z(mod\ p)\] 其中\((y,p)=1\) 做 ...
- Java虚拟机对象存活标记及垃圾收集算法解析
一.对象存活标记 1. 引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1:当引用失效时,计数器就减1:任何时刻计数器都为0的对象就是不可能再被使用的. 引用计数算法(Re ...
随机推荐
- Apache Pulsar 社区周报:08-15 ~ 08-21
关于 Apache Pulsar Apache Pulsar 是 Apache 软件基金会顶级项目,是下一代云原生分布式消息流平台,集消息.存储.轻量化函数式计算为一体,采用计算与存储分离架构设计,支 ...
- java生成四位随机数,包含数字和字母 区分大小写,特别适合做验证码,android开发
private String generateWord() { String[] beforeShuffle = new String[] { "2", "3" ...
- Spine学习九 - 冰冻效果
想象这样一个效果,一个人被冰霜攻击命中,然后这个人整个就被冰冻了,那么spine动画要如何实现这个效果呢? 1.首先需要一个Spine动画,这个动画应该是相对静止的,因为人物已经被冰冻了,那么这个人儿 ...
- zabbix-4.0-监控服务器的ping告警设置
问题:一直在困惑如果一台服务器的网络发生故障或者断开时,怎么第一时间发现并去排查. 思路:利用zabbix平台监控服务器,监控ping这一项,设置一个报警,并使用脚本去提醒与通知,可使用邮件报警/短信 ...
- Pinpoint 一款强大的APM工具
背景 程序的监控一直是程序员最头痛的事情之一,现网程序有问题怎么办?看进程看端口 top/free/df 三件套?网络抓包?看日志?所以为了满足这些初级需求很多公司都做了主机监控,进程端口监听等功能, ...
- Go语言使用swagger生成接口文档
swagger介绍 Swagger本质上是一种用于描述使用JSON表示的RESTful API的接口描述语言.Swagger与一组开源软件工具一起使用,以设计.构建.记录和使用RESTful Web服 ...
- 剑指 Offer 53 - I. 在排序数组中查找数字 I
题目描述 统计一个数字在排序数组中出现的次数. 示例1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: 2 示例2: 输入: nums = [5,7,7,8,8, ...
- Activiti7 绑定业务主键以及流程定义 流程实例的挂起和激活
绑定业务主键businessKey /** * 绑定业务主键 */ @Test public void bindingBusinessKey() { // 获取RuntimeService Runti ...
- Java里一个线程两次调用start()方法会出现什么情况
Java的线程是不允许启动两次的,第二次调用必然会抛出IllegalThreadStateException,这是一种运行时异常,多次调用start被认为是编程错误. 如果业务需要线程run中的代码再 ...
- .NET实现可交互的WINDOWS服务(转载自CSDN"烈火蜓蜻")
Windows 服务应用程序在不同于登录用户的交互区域的窗口区域中运行.窗口区域是包含剪贴板.一组全局原子和一组桌面对象的安全对象.由于 Windows 服务的区域不是交互区域,因此 Windows ...