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{yk}{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;
}

BSGS算法及拓展的更多相关文章

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

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

  2. BSGS算法

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

  3. bzoj2242: [SDOI2011]计算器 && BSGS 算法

    BSGS算法 给定y.z.p,计算满足yx mod p=z的最小非负整数x.p为质数(没法写数学公式,以下内容用心去感受吧) 设 x = i*m + j. 则 y^(j)≡z∗y^(-i*m)) (m ...

  4. [BSGS算法]纯水斐波那契数列

    学弟在OJ上加了道"非水斐波那契数列",求斐波那契第n项对1,000,000,007取模的值,n<=10^15,随便水过后我决定加一道升级版,说是升级版,其实也没什么变化,只 ...

  5. BSGS算法及扩展

    BSGS算法 \(Baby Step Giant Step\)算法,即大步小步算法,缩写为\(BSGS\) 拔山盖世算法 它是用来解决这样一类问题 \(y^x = z (mod\ p)\),给定\(y ...

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

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

  7. BSGS算法及其扩展

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

  8. BSGS算法学习笔记

    从这里开始 离散对数和BSGS算法 扩展BSGS算法 离散对数和BSGS算法 设$x$是最小的非负整数使得$a^{x}\equiv b\ \ \ \pmod{m}$,则$x$是$b$以$a$为底的离散 ...

  9. bsgs算法详解

    例题  poj 2417bsgs  http://poj.org/problem?id=2417 这是一道bsgs题目,用bsgs算法,又称大小步(baby step giant step)算法,或者 ...

随机推荐

  1. 如何优雅的使用vue+Dcloud(Hbuild)开发混合app

    如何优雅的使用vue+Dcloud(Hbuild)开发混合app 最近在做混合app,前端框架用的是vue,打包app使用的是Dcloud,不过在开发过程中有一点不爽的是,如果想使用Dcloud提供的 ...

  2. C语言学习7

    结构体数组:实现简易通讯录 #include <stdio.h> #include <stdlib.h> #define NUM 3 struct person { ]; ]; ...

  3. hihoCoder#1062 最近公共祖先·

    原题地址 A和A的共同祖先是A,即使A没有在之前的家谱中出现过!被这个坑了,WA了很久... 比如:小头爸爸是大头儿子他爹,问:隔壁王叔叔和隔壁王叔叔的最近祖先是谁?,答:隔壁王叔叔. 代码: #in ...

  4. hihoCoder#1051 补提交卡

    原题地址 简单贪心 首先,补提交卡应该连续使用,其次,补提交卡应该全部用掉(如果补提交卡多于未提交天数则额外处理) 所以,依次遍历未提交日期,计算:从当前位置开始,用M张补提交卡覆盖后面连续M个数字, ...

  5. 【数轴涂色+并查集路径压缩+加速】C. String Reconstruction

    http://codeforces.com/contest/828/problem/C [题意] [思路] 因为题目保证一定有解,所有优化时间复杂度的关键就是不要重复染色,所以我们可以用并查集维护区间 ...

  6. springData Jpa 快速入门

    前言: 数据持久化的操作,一般都要由我们自己一步步的去编程实现,mybatis通过我们编写xml实现,hibernate也要配置对应的xml然后通过创建session执行crud操作.那么有没有这样一 ...

  7. Linux下汇编语言学习笔记40 ---

    这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...

  8. Delphi:校验手机号及身份证号

    //校验手机号  function IsMobileNumber( num:string ):boolean;   begin     Result:=False;     if length( tr ...

  9. hadoop(1)入门

    hadoop入门(一)   一.概述 1.什么是hadoop hadoop不仅是一个用于存储分布式文件系统,还是设计用来在有通用计算设备组成的大型集群上执行的分布式应用的基础框架. hadoop框架最 ...

  10. Ubuntu16.04安装deb文件时提示:此软件来自第三方且可能包含非自由组件

    解决方式: 1.在Ubuntu软件中心安装GDebi. 2.安装好之后,选择这个要安装的deb文件右键,打开方式选择GDebi,然后输入管理员密码等待安装,期间如果不行需要重试几次. 3.另外的方法, ...