2023.1.16 [模板]BSGS/exBSGS

全称Boy Step Girl Step

给定一个质数 p,以及一个整数 a,一个整数 b,现在要求你计算一个最小的非负整数 l,

满足\(a^x \equiv b (mod p)\)

算法流程

设t = \(\lceil \sqrt p \rceil\) ,x = i * t - m (0\(\leq\)i\(\leq\)t , 0\(\leq\)m\(\lt\)t - 1)

\(a^{i * t - b} \equiv b\) (mod p)

\(({a^t})^i \equiv b * a^m\) (mod p)

我们建立一个map,将b * \(a^0\) ~ b * \(a^{t - 1}\) 全部推进去,将值与指数建立映射关系,然后再枚举i,递推算出左式,判断map中是否有值,如果有值则返回答案ans = i * t - map[val]

时间复杂度O(\(\sqrt p\))

inline int BSGS(int a,int b,int p)//a ^ x = b (% p)
{
map <int,int> q;
int t = sqrt(p);
for(int i = 0;i <= t - 1;i++)
q[(1ll * ksm(a,i,p) * b % p)] = i;
int c = ksm(a,t,p);
for(int i = 1;i <= t;i++)
{
int now = ksm(c,i,p);
if(q.find(now) != q.end())
{
int x = q[now];
return i * t - x;
}
}
return -1;
}

exBSGS

那么如果a,p不互质呢?

设d = gcd(a,p);

对于一个同余方程\(a^x \equiv b\) (mod p)

我们可以把它转化成二元一次不定方程的形式 \(a^x\) + py = b

给a分离系数得到 a\(a^{x-1}\) + py = b

想办法消去d,\(\frac ad a^{x-1} + \frac pd y = \frac bd\)

多次迭代,直到d = 1,可以得到以下柿子

\(\frac a{d_1d_2...d_k} a^{x-k} + \frac p{d_1d_2...d_k} y = \frac b{d_1d_2...d_k}\)

转化为原式 \(\frac a{d_1d_2...d_k} a^{x-k} \equiv \frac b{d_1d_2...d_k}\) \(mod (\frac p{d_1d_2...d_k})\)

记录一个变量r = \(\frac a{d_1d_2...d_k} a^{x-k}\),每次迭代时累乘上\(\frac a{d_i}\)

把r移向同余号右侧,那么我们就得到了一个标准的BSGS,但是同余运算中不能左右同除,于是我们用exgcd算出r关于\(\frac p{d_1d_2...d_k}\)的逆元,然后两边同乘以逆元,在跑一边BSGS即可

Code

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
typedef long long ll;
using namespace std;
inline int ksm(ll base,int pts,int mod)
{
ll ans = 1;
for(;pts > 0;pts >>= 1,base = 1ll * base * base % mod)
if(pts & 1)
ans = ans * base % mod;
return ans;
}
inline int BSGS(int a,ll b,int p)//a ^ x = b (% p)
{
__gnu_pbds::gp_hash_table <ll,int> q;
b %= p;
int t = ceil(sqrt(p));
for(int i = 0;i <= t;i++)
q[(ksm(a,i,p) * b % p)] = i;
ll c = ksm(a,t,p),now = 1;
for(int i = 1;i <= t;i++)
{
now = now * c % p;
if(q.find(now) != q.end())
{
int x = q[now];
return (i * t - x + p) % p;
}
}
return -1;
}
inline int exgcd(ll &x,int &y,int a,int b)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
int ret = exgcd(x,y,b,a % b);
int k = y;
y = x - (a / b) * y;
x = k;
return ret;
}
inline int gcd(int a,int b)
{
if(b == 0) return a;
return gcd(b,a % b);
}
ll ot = 1;
inline int exBSGS(int a,int b,int p)
{
if(ot == b) return 0;
int x,y;
int d = gcd(a,p);
if(d == 1)
{
ll inv;
exgcd(inv,y,ot,p);
inv = ((inv % p) + p) % p;
return BSGS(a,(1ll * inv * b) % p,p);
}
if(b % d != 0) return -1;
ot = ot * (a / d) % (p / d);
int ret = exBSGS(a,b / d,p / d);
if(ret == -1) return -1;
return ret + 1;
}
signed main()
{
int a,p,b;
scanf("%d%d%d",&a,&p,&b);
while(a || p || b)
{
a %= p;b %= p;
if(b == 1 || p == 1)
{
puts("0");
scanf("%d%d%d",&a,&p,&b);
continue;
}
ot = 1;
int k = exBSGS(a,b,p);
if(k == -1)
printf("No Solution\n");
else
printf("%lld\n",k);
scanf("%d%d%d",&a,&p,&b);
}
return 0;
}

语法tip:

C++中有一种比map 和 unordered_map更快的hash映射gp_hash_table,用法和普通map相同

头文件

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>

命名空间

using namespace __gnu_pbds

定义hash

(__gnu_pbds::)gp_hash_table <int,int> q;

最新文章

  1. Ubuntu14.04安装python3.5
  2. Redis持久化
  3. maven实战_01_搭建maven开发环境
  4. 关于内存的5个函数(malloc,VirtualAlloc,GlobalAlloc,LocalAlloc,HeapAlloc)
  5. java中 正则表达式的使用
  6. Octave下载
  7. tcp断开的4次挥手
  8. jQuery toggle() 方法与实例以及代替方法。
  9. 内存(MRC)
  10. libcurl的使用问题“Expect100-continue”
  11. J2EE走向成功路-01-Struts2 配置
  12. mysql优化一之查询优化
  13. postgresql :: FATAL: could not write init file
  14. Oarcle之单行函数(下)
  15. Windows Server 2003下DHCP服务器的安装与简单配置图文教程
  16. c++沉思录 学习笔记 第五章 代理类
  17. 从零开始——MySql01
  18. poj2182 逆推暴力
  19. 两个Integer比较大小需要注意的误区
  20. 随笔——python截取http请求报文响应头

热门文章

  1. go GMP
  2. JUnit 5 单元测试教程
  3. 【云原生 · Kubernetes】Kubernetes Node的隔离与恢复
  4. win11如何双屏幕(1台主机2块显示器)
  5. CPU TLB原理 [转载好文]
  6. 基于Sklearn机器学习代码实战
  7. 面试官:介绍一下 Redis 三种集群模式
  8. Vue2组件间通讯
  9. AI绘画提示词创作指南:DALL&#183;E 2、Midjourney和 Stable Diffusion最全大比拼 ⛵
  10. 【终极解决办法】pyinstaller打包exe没有错误,运行exe提示Failed to execute script &#39;mainlmageWindows&#39; due tounhandled exception: No module named &#39;docx&#39;