博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BSGS算法及拓展
阅读量:5327 次
发布时间:2019-06-14

本文共 2514 字,大约阅读时间需要 8 分钟。

定义

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

一般问题形式:求使得\(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]\)

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

拓展\(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
#include
#include
#include
#include
#include
#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

转载于:https://www.cnblogs.com/yanshannan/p/9739312.html

你可能感兴趣的文章
给mysql数据库字段值拼接前缀或后缀。 concat()函数
查看>>
迷宫问题
查看>>
【FZSZ2017暑假提高组Day9】猜数游戏(number)
查看>>
泛型子类_属性类型_重写方法类型
查看>>
eclipse-将同一个文件分屏显示
查看>>
mysql5.x升级至mysql5.7后导入之前数据库date出错的解决方法!
查看>>
对闭包的理解
查看>>
练习10-1 使用递归函数计算1到n之和(10 分
查看>>
Oracle MySQL yaSSL 不明细节缓冲区溢出漏洞2
查看>>
windows编程ASCII问题
查看>>
.net webService代理类
查看>>
Code Snippet
查看>>
Node.js Express项目搭建
查看>>
zoj 1232 Adventure of Super Mario
查看>>
1201 网页基础--JavaScript(DOM)
查看>>
组合数学 UVa 11538 Chess Queen
查看>>
oracle job
查看>>
Redis常用命令
查看>>
XML学习笔记(二)-- DTD格式规范
查看>>
IOS开发学习笔记026-UITableView的使用
查看>>