BSGS算法及拓展

https://www.zybuluo.com/ysner/note/1299836

定义

一种用来求解高次同余方程的算法。

一般问题形式:求使得\(y^x\equiv z(mod\ p)\)的最小非负\(x\)。

\(BSGS\)算法

要求\(p\)是质数。

由费马小定理可知,\(y^{p-1}\equiv1(mod\ p)\),所以暴力枚举只要枚举到\(p?1\)即可。

但是由于\(p\)一般都很大,所以一般都跑不动。。。

优化算法\(ing...\)

现在令\(x=mi?j\)(其中\(m=\lceil\sqrt p\rceil\))。

则方程可化为\(y^{mi-j}\equiv z(mod\ p)\),

\(y^{mi}\equiv y^jz(mod\ p)\)

然后可以发现\(j<m\)(否则\(x\)就是负数)

所以我们可以暴力枚举\(j\),与所得\(y^jz(mod\ p)\)的存在哈希表里,然后再暴力枚举\(i\),最后得出结果。

还要注意一些边界:

  • \(y!=0\)
  • \(z=1\)时\(puts("no\ solution")\)
  • \(i\)的边界是\([1,m+1]\)

一道Poj上的板子题

[SDOI2011]计算器

struct Hash_Table
{
  int h[N],cnt;
  struct Edge{int u,v,nxt;}e[N*10];
  il void clear(){memset(h,-1,sizeof(h));cnt=0;}
  il void add(re int u,re int v,re int w){e[++cnt]=(Edge){w,v,h[u]};h[u]=cnt;}
  il int Query(re int x)
  {
    re int t=x%mod;
    for(re int i=h[t];i+1;i=e[i].nxt)
      if(e[i].u==x) return e[i].v;
    return -1;
  }
  il void solve(re int y,re int z,re int p)
  {
    y%=p;z%=p;
    if(!y) {puts("no solution");return;}
    if(z==1) {puts("0");return;}
    re int m=sqrt(p)+1;clear();
    for(re int i=0,t=z;i<m;++i,t=1ll*t*y%p) add(t%mod,i,t);
    for(re int i=1,tt=ksm(y,m,p),t=tt;i<=m+1;++i,t=1ll*t*tt%p)
      {
    re int j=Query(t);if(j==-1) continue;
    printf("%d\n",i*m-j);return;
      }
    puts("no solution");
  }
}BSGS;
int main()
{
  re int y,p,z;
  while(scanf("%d%d%d",&p,&y,&z)!=EOF)
    {
      BSGS.solve(y,z,p);
    }
  return 0;
}

拓展\(BSGS\)算法

不要求\(p\)是质数。

那就说明很可能\(gcd(y,p)!=1\),不满足费马小定理。

费马小定理提供了枚举上限,没有它这种问题就不好做了。。。

想想怎么把\(y,p\)约分。

令\(t=gcd(y,p)\)。

把方程改写成等式形式:\[y^x+kp=z\]

分析一下,可以发现\(z\)一定是\(t\)的倍数。

除\(t\):\[\frac{y}{t}y^{x-1}+\frac{p}{t}k=\frac{z}{t}\]

接下来再次检查\(gcd(y,\frac{z}{t})\)是否为\(1\),若否,说明还可以继续约分,理由同上。

最后形式为(那个\(t\)反正是个正整数)\[\frac{y^k}{t}y^{x-k}\equiv\frac{z}{t}(mod\ \frac{p}{t})\]

注意边界:

  • 如果\(t>1\)并且\(z\%t>0\),方程无解
  • 约分完的石子带到普通\(BSGS\)中时要带系数

咕谷模板题

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define il inline
#define re register
#define ll long long
#define fp(i,a,b) for(re int i=a;i<=b;++i)
#define fq(i,a,b) for(re int i=a;i>=b;--i)
using namespace std;
const int N=5e4,mod=45807;
il ll ksm(re ll S,re ll n,re int p)
{
  re ll T=S;S=1;
  while(n)
    {
      if(n&1) S=S*T%p;
      T=T*T%p;
      n>>=1;
    }
  return S;
}
struct Hash_Table
{
  int h[N],cnt;
  struct Edge{int u,v,nxt;}e[N*10];
  il void clear(){memset(h,-1,sizeof(h));cnt=0;}
  il void add(re int u,re int v,re int w){e[++cnt]=(Edge){w,v,h[u]};h[u]=cnt;}
  il int Query(re int x)
  {
    re int t=x%mod;
    for(re int i=h[t];i+1;i=e[i].nxt)
      if(e[i].u==x) return e[i].v;
    return -1;
  }
  il void solve(re int y,re int z,re int p)
  {
    if(z==1) {puts("0");return;}
    re int k=0,a=1;
    while(233)
      {
    re int t=__gcd(y,p);if(t==1) break;
    if(z%t) {puts("No Solution");return;}
    z/=t;p/=t;++k;a=1ll*a*y/t%p;
    if(z==a) {printf("%d\n",k);return;}//有意思的地方
      }
    re int m=sqrt(p)+1;clear();
    for(re int i=0,t=z;i<m;++i,t=1ll*t*y%p) add(t%mod,i,t);
    for(re int i=1,tt=ksm(y,m,p),t=1ll*a*tt%p;i<=m+1;++i,t=1ll*t*tt%p)
      {
    re int j=Query(t);if(j==-1) continue;
    printf("%d\n",i*m-j+k);return;
      }
    puts("No Solution");
  }
}BSGS;
int main()
{
  re int y,p,z;
  while(scanf("%d%d%d",&y,&p,&z))
    {
      if(!p&&!y&&!z) break;
      BSGS.solve(y,z,p);
    }
  return 0;
}

原文地址:https://www.cnblogs.com/yanshannan/p/9739312.html

时间: 2024-11-08 04:09:20

BSGS算法及拓展的相关文章

bzoj2242: [SDOI2011]计算器 &amp;&amp; BSGS 算法

BSGS算法 给定y.z.p,计算满足yx mod p=z的最小非负整数x.p为质数(没法写数学公式,以下内容用心去感受吧) 设 x = i*m + j. 则 y^(j)≡z?y^(-i*m)) (mod p) 则 y^(j)≡z?ine(y^(i*m)) (mod p)(逆元) 由费马小定理y^(p-1)≡1 (mod p) 得 ine(y^m) = y^(p-m-1)  ine(y^(i*m)≡ine(y^((i?1)m))?y^(p-m-1)  1.首先枚举同余符号左面,用一个hash保存

BSGS算法学习小记(大步小步算法)

简介 先看一个式子xy≡z(modp),z是质数 现在只知道x和z,要求y. 大步小步算法(BSGS,Baby Steps Giant Steps)就是解决这个问题. 算法流程 暴搜的枚举范围 根据费马小定理:xz?1≡1. 如果y已经枚举到了z-1了,继续枚举的话就会产生循环. 所以,在暴搜中y的枚举范围就是0--z-1. 如何优化暴搜 我们想一想可不可以用分块来解决枚举的y. 把y分成p?1????√分别枚举行不行? 设m=p?1????√,y=a?m+b,这样枚举a和b就相当于分块枚举了.

BSGS算法+逆元 POJ 2417 Discrete Logging

POJ 2417 Discrete Logging Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4860   Accepted: 2211 Description Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarith

BSGS算法_Baby steps giant steps算法(无扩展)最强详解,你从未见过的详细

Baby Steps-Varsity Giant Step-Astronauts(May'n?椎名慶治) 阅读时可以听听这两首歌,加深对这个算法的理解.(Baby steps少女时代翻唱过,这个原唱反而不是很有名……Giant Step就比较碉,是一个假面骑士片的插曲,由超碉的May'n和一个人建立的临时组合唱的,怕不怕) 这个主要是用来解决这个题: A^x=B(mod C)(C是质数),都是整数,已知A.B.C求x. 我在网上看了好多介绍,觉得他们写得都不够碉,我看不懂…于是我也来写一发. 先

BSGS算法初探

前言 $BSGS$算法,全称$Baby Step Giant Step$,即大小步算法.某些奆佬也称其为拔(Ba)山(Shan)盖(Gai)世(Shi)算法. 它的主要作用是求解形式如$x^t\equiv y(mod MOD)$的式子中$t$的值. 而且,它是一个简单易懂的算法(毕竟连我这样的数学渣渣都能理解). 一个简单的性质 首先,我们需要知道一个简单的性质. 由费马小定理可得,$x^{MOD-1}\equiv1(mod MOD)$. $Link$ 费马小定理详见博客筛素数方法(二)-- 费

BSGS算法!

求解关于x的方程 a^x=z(mod p),其中gcd(a,p)=1. 做法的话并不难,但是要搞懂细节还蛮多的. bsgs算法是这样的:x可以写成i*m-j的形式(这里m取值随意,但是取√p上取整时跑的最快) a^(im-j)≡z(mod p) 推得  a^im≡z*(a^j) 那么我们枚举j的值从0--(m-1),将算出的z*(a^j)加入map里面 再枚举i从1-m,将每次算出的a^im的结果去map中匹配 若匹配到,x=i*m-j. 细节 1.i的范围从1到m 证明: a ^ x Ξ b

BSGS算法(大小步算法)

$BSGS$ 算法 $Baby\ Steps\ Giant\ Steps$. 致力于解决给定两个互质的数 $a,\ p$ 求一个最小的非负整数 $x$ 使得 $a^x\equiv b(mod\ p)$ 其中 $b$ 为任意正整数,$2≤a<p$,$2≤b<p$ 该算法使用的原理与欧拉定理有关,其中$a,\ p$互质 $a^{\phi (p)}\equiv 1(mod\ p)$ 又因为 $a^0\equiv 1(mod\ p)$ 所以$0到\phi p$是一个循环节,也就是说该算法最多查找$\p

目标检测最全论文集锦引用地址 最新进展和研究成果 2019最火目标检测算法centernet 拓展想法以及拓展研究的思路

目标检测最全论文集锦引用地址 最新进展和研究成果 2019最火目标检测算法centernet 拓展想法以及拓展研究的思路 待办 经典论文集锦 https://zhuanlan.zhihu.com/p/36818086 https://handong1587.github.io/deep_learning/2015/10/09/object-detection.html 目标检测最新进展与研究 https://zhuanlan.zhihu.com/p/96115519 centernet思路梳理

高次不定方程BSGS算法

学习数学真是一件赛艇的事. BSGS名字听起来非常有意思,力拔山兮气盖世,北上广深,小步大步...算法其实更有意思,它是用来求解一个方程的 \(A^x≡B mod P\) 是不是特别眼熟,有几个式子长的特别像,先观察一下: 一:快速幂: 求\(A^B mod P\)的值 二:乘法逆元 \(A*x ≡ 1 (mod P)\) 或者 \(A*x ≡ B (mod P)\) 三:欧拉定理 \(A^{φ(P)}≡ 1 (mod P)\) (A,P互质) 四:费马小定理 \(A^{P-1} ≡ 1 (mo