BSGS (大步小步算法)

已知\(a、b、 c\),求\(x\)。令\(a^x \equiv b \pmod c\)。

步骤

\[m = \lceil \sqrtc\ \rceil $$$$x = i*m-j\ \ (i\in[1, m], j\in[0, m])$$$$a^{i*m-j} \equiv b \pmod c$$$$a^{i*m}\equiv b*a^j \pmod c
\]

枚举\(a^j(j\in[0, m])\)放入\(hash\)表里面,再枚举\(a^{i*m}\),在\(hash\)表里面找有没有相同,如若有相同的那么就存在。

如果在询问较多的情况下,可以把\(bm = \lceil c^{\frac{2}{3}}\rceil\)、\(gm = \lceil c^{\frac{1}{3}}\rceil\)\((i\in[1,gm],j\in[0, bm])\)

实现代码

struct Hash{
int head[maxm], cnt, mod;
struct Node{
int v, id, next;
}node[maxn];
void init(){
mes(head, -1);
cnt = 0;
mod = 1333331;
}
void insert(int x, int id){
int u = x%mod;
node[++cnt].v = x;
node[cnt].id = id;
node[cnt].next = head[u];
head[u] = cnt;
}
int find(int x){
int u = x%mod;
for(int i = head[u]; ~i; i = node[i].next){
if(node[i].v == x)
return node[i].id;
}
return -1;
}
}hs; ll qpow(ll a, ll b, int mod){
ll ans = 1;
while(b){
if(b&1)
ans = ans*a%mod;
a = a*a%mod;
b /= 2;
}
return ans;
}
struct BSGS{
int bm, gm, a, b, x0, p; void init(){
bm = (int)ceil(pow(p, 2.0/3));
gm = (int)ceil(pow(p, 1.0/3));
ll ans = 1;
hs.init();
for(int i = 0; i <= bm; i++){ //a^(i*bm - j)%p = b;
hs.insert(ans, i);
ans = ans*a%p;
}
} ll get(ll v){
v = qpow(v, p-2, p);
ll num = qpow(a, bm, p);
for(int i = 1; i <= gm; i++){
v = v*num%p;
int ans = hs.find(v);
if(ans != -1)
return 1ll*i*bm - ans;
}
return -1;
}
}bsgs;

例题

牛客多校训练营第五场 - generator 2

\(x_n = (a*x_{n-1} + b)\%p\),给你\(n、x_0、a、b、p\),\(Q\)个询问在\(x_0,x_1,x_2...,x_{n-1}\)找到最小符合\(x_i = v\)的\(i\),不存在输出\(-1\)。

思路

\[x_n = a*x_{n-1} + b$$$$x_n = a^n *x_0+b*\frac{1-a^n}{1-a}$$$$a^n = \frac{(a-1)_*x_n+b}{(a-1)*x_0+b}$$$$x_n = v, 令B = \frac{(a-1)_*v+b}{(a-1)*x_0+b}$$所以就是求$$a^n \equiv B\pmod p
\]

\(a = 0、a = 1\)的情况要特殊考虑一下

AC代码

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int> typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e6 + 10;
const int maxm = 2e6 + 10;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std; int n, m;
int cas, tol, T;
struct Hash{
int head[maxm], cnt, mod;
struct Node{
int v, id, next;
}node[maxn];
void init(){
mes(head, -1);
cnt = 0;
mod = 1333331;
}
void insert(int x, int id){
int u = x%mod;
node[++cnt].v = x;
node[cnt].id = id;
node[cnt].next = head[u];
head[u] = cnt;
}
int find(int x){
int u = x%mod;
for(int i = head[u]; ~i; i = node[i].next){
if(node[i].v == x)
return node[i].id;
}
return -1;
}
}hs; ll qpow(ll a, ll b, int mod){
ll ans = 1;
while(b){
if(b&1)
ans = ans*a%mod;
a = a*a%mod;
b /= 2;
}
return ans;
}
struct BSGS{
int bm, gm, a, b, x0, p; void init(){
bm = (int)ceil(pow(p, 2.0/3));
gm = (int)ceil(pow(p, 1.0/3));
ll ans = 1;
hs.init();
for(int i = 0; i <= bm; i++){ //a^(i*bm - j)%p = b;
hs.insert(ans, i);
ans = ans*a%p;
}
} ll get(ll v){
v = qpow(v, p-2, p);
ll num = qpow(a, bm, p);
for(int i = 1; i <= gm; i++){
v = v*num%p;
int ans = hs.find(v);
if(ans != -1)
return 1ll*i*bm - ans;
}
return -1;
}
}bsgs; int main() {
scanf("%d", &T);
while(T--){
ll n,x0, a, b, p;
scanf("%lld%lld%lld%lld%lld", &n, &x0, &a, &b, &p);
bsgs.x0 = x0; bsgs.a = a; bsgs.b = b; bsgs.p = p;
bsgs.init();
int q;ll v;
scanf("%d", &q);
ll inv = ((a-1)*x0%p+b+p)%p;
if(inv == 0){
while(q--){
scanf("%lld", &v);
if(x0 == v)
printf("0\n");
else
printf("-1\n");
}
continue;
}
if(a == 0){
while(q--){
scanf("%lld", &v);
if(v == x0) //x = x0;
printf("0\n");
else if(v == b) //xn = b
printf("1\n");
else
printf("-1\n"); //无解
continue;
}
continue;
}
if(a == 1){ //xn = x0 + nb;
ll invb = qpow(b, p-2,p);
while(q--){
scanf("%lld", &v);
if(b == 0){
if(v == x0)
printf("0\n");
else
printf("-1\n");
}
else{ // n = (v - x0)/b;
ll ans = ((v-x0+p) % p * invb%p + p)%p;
if(ans < n)
printf("%lld\n", ans);
else
printf("-1\n");
}
}
continue;
}
inv = qpow(inv, p-2, p);
while(q--){
scanf("%lld", &v);
v = ((a-1)*v%p+b+p)%p*inv%p;
ll ans = bsgs.get(v);
if(ans == -1 || ans >= n)
printf("-1\n");
else
printf("%lld\n", ans);
}
}
return 0;
}

BSGS算法(模板)的更多相关文章

  1. uva11916 bsgs算法逆元模板,求逆元,组合计数

    其实思维难度不是很大,但是各种处理很麻烦,公式推导到最后就是一个bsgs算法解方程 /* 要给M行N列的网格染色,其中有B个不用染色,其他每个格子涂一种颜色,同一列上下两个格子不能染相同的颜色 涂色方 ...

  2. 【codevs 1565】【SDOI 2011】计算器 快速幂+拓展欧几里得+BSGS算法

    BSGS算法是meet in the middle思想的一种应用,参考Yveh的博客我学会了BSGS的模版和hash表模板,,, 现在才会hash是不是太弱了,,, #include<cmath ...

  3. BSGS算法

    BSGS算法 我是看着\(ppl\)的博客学的,您可以先访问\(ppl\)的博客 Part1 BSGS算法 求解关于\(x\)的方程 \[y^x=z(mod\ p)\] 其中\((y,p)=1\) 做 ...

  4. BSGS算法及其扩展

    bsgs算法: 我们在逆元里曾经讲到过如何用殴几里得求一个同余方程的整数解.而\(bsgs\)就是用来求一个指数同余方程的最小整数解的:也就是对于\(a^x\equiv b \mod p\) 我们可以 ...

  5. POJ2417 Discrete Logging【BSGS】(模板题)

    <题目链接> 题目大意: P是素数,然后分别给你P,B,N三个数,然你求出满足这个式子的L的最小值 : BL== N (mod P). 解题分析: 这题是bsgs算法的模板题. #incl ...

  6. POJ2417 Discrete Logging | A,C互质的bsgs算法

    题目: 给出A,B,C 求最小的x使得Ax=B  (mod C) 题解: bsgs算法的模板题 bsgs 全称:Baby-step giant-step 把这种问题的规模降低到了sqrt(n)级别 首 ...

  7. BSGS算法及拓展

    https://www.zybuluo.com/ysner/note/1299836 定义 一种用来求解高次同余方程的算法. 一般问题形式:求使得\(y^x\equiv z(mod\ p)\)的最小非 ...

  8. BSGS算法解析

    前置芝士: 1.快速幂(用于求一个数的幂次方) 2.STL里的map(快速查找) 详解 BSGS 算法适用于解决高次同余方程 \(a^x\equiv b (mod p)\) 由费马小定理可得 x &l ...

  9. 匈牙利 算法&模板

    匈牙利 算法 一. 算法简介 匈牙利算法是由匈牙利数学家Edmonds于1965年提出.该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法. 二分图的定义: 设G=(V,E)是一个 ...

  10. Tarjan 算法&模板

    Tarjan 算法 一.算法简介 Tarjan 算法一种由Robert Tarjan提出的求解有向图强连通分量的算法,它能做到线性时间的复杂度. 我们定义: 如果两个顶点可以相互通达,则称两个顶点强连 ...

随机推荐

  1. statistics——数学统计函数

    statistics——数学统计函数 转自:https://blog.csdn.net/zhtysw/article/details/80005410 资源代码位置:Lib/statistixs.py ...

  2. git清空远程仓库

    需求背景:因为用jenkins连接了git仓库,有时候job构建出现问题,需要排查问题,但是呢,真实的项目代码量非常pang大,所以就需要建1个测试仓库,使用最少量的代码能复现自己的问题就好. 这就需 ...

  3. php面向对象的重写与重载

    重写: 就是当子类继承父类的一些方法后,子类又在其内部定义了相同的方法,则这个新定义的方法会覆盖继承而来的父类的方法,子类只能调用其内部定义的方法. 有以下几点要求: 1.当一个父类和子类有一个方法, ...

  4. 搞死人不偿命的 Bank系统

    每一个成功者都有一个开始.勇于开始,才能够找到通往成功的路. 最近C#进行到第三章:升级Mybank,发现这是一个我个人觉得比较难搞的一个东西,一下是我对Bank系统难点的叙述,请大神笔下留情~ 1. ...

  5. VUEJS(vuejs) 数组数据不及时刷新

    在Vue对象中的methods属性中构建一个方法用于刷新data使用Vue.set方法进行手动刷新methods:{update:function(o){Vue.set(this,'list',o); ...

  6. 不同vlan之间相互通信

    不同VLAN之间相互通信的两种方式 (单臂路由.三层交换) 试验目的: 1.通过单臂路由实现不同VLAN之间的通信 2.通过三层交换路由功能实现不同VLAN之间的通信   网络拓扑图: 1.单臂路由实 ...

  7. Eclipse + pydev插件

    在Eclipse中安装pydev插件 启动Eclipse, 点击Help->Install New Software...   在弹出的对话框中,点Add 按钮.  Name中填:Pydev,  ...

  8. 关于this、Echarts中的data

    this是指当前对象 移除class的jQuery代码:$('ur.nav li:eq(0)').removeClass('active') 添加class的jQuery代码:$('ur.nav li ...

  9. python 可变类型和不可变类型

    1. 什么是不可变类型变量对应的值中的数据是不能被修改,如果修改就会生成一个新的值从而分配新的内存空间.不可变类型: 数字(int,long,float) 布尔(bool) 字符串(string) 元 ...

  10. shell 删除项目日志

    删除半年之前的日志 find 后面紧跟目录 .为当前目录 -type f 指定查找的是文件 -mtime +180  查找180天之前的 -name  文件名筛选 -exec -rm -rf  执行的 ...