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]\)
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算法及拓展的更多相关文章
- 【codevs 1565】【SDOI 2011】计算器 快速幂+拓展欧几里得+BSGS算法
BSGS算法是meet in the middle思想的一种应用,参考Yveh的博客我学会了BSGS的模版和hash表模板,,, 现在才会hash是不是太弱了,,, #include<cmath ...
- BSGS算法
BSGS算法 我是看着\(ppl\)的博客学的,您可以先访问\(ppl\)的博客 Part1 BSGS算法 求解关于\(x\)的方程 \[y^x=z(mod\ p)\] 其中\((y,p)=1\) 做 ...
- bzoj2242: [SDOI2011]计算器 && BSGS 算法
BSGS算法 给定y.z.p,计算满足yx mod p=z的最小非负整数x.p为质数(没法写数学公式,以下内容用心去感受吧) 设 x = i*m + j. 则 y^(j)≡z∗y^(-i*m)) (m ...
- [BSGS算法]纯水斐波那契数列
学弟在OJ上加了道"非水斐波那契数列",求斐波那契第n项对1,000,000,007取模的值,n<=10^15,随便水过后我决定加一道升级版,说是升级版,其实也没什么变化,只 ...
- BSGS算法及扩展
BSGS算法 \(Baby Step Giant Step\)算法,即大步小步算法,缩写为\(BSGS\) 拔山盖世算法 它是用来解决这样一类问题 \(y^x = z (mod\ p)\),给定\(y ...
- uva11916 bsgs算法逆元模板,求逆元,组合计数
其实思维难度不是很大,但是各种处理很麻烦,公式推导到最后就是一个bsgs算法解方程 /* 要给M行N列的网格染色,其中有B个不用染色,其他每个格子涂一种颜色,同一列上下两个格子不能染相同的颜色 涂色方 ...
- BSGS算法及其扩展
bsgs算法: 我们在逆元里曾经讲到过如何用殴几里得求一个同余方程的整数解.而\(bsgs\)就是用来求一个指数同余方程的最小整数解的:也就是对于\(a^x\equiv b \mod p\) 我们可以 ...
- BSGS算法学习笔记
从这里开始 离散对数和BSGS算法 扩展BSGS算法 离散对数和BSGS算法 设$x$是最小的非负整数使得$a^{x}\equiv b\ \ \ \pmod{m}$,则$x$是$b$以$a$为底的离散 ...
- bsgs算法详解
例题 poj 2417bsgs http://poj.org/problem?id=2417 这是一道bsgs题目,用bsgs算法,又称大小步(baby step giant step)算法,或者 ...
随机推荐
- CentOS 7.4 源码编译安装 Redis
一.CentOS 7.4 源码编译安装 Redis 1.下载源码并解压 wget http://download.redis.io/releases/redis-4.0.10.tar.gz tar ...
- Python中的列表(3)
我们创建的列表元素的顺序是无法预测的,因为我们无法控制用户提供数据的顺序. 为了组织列表中的元素,所以Python帮我们提供一些方法用来排序列表中的元素. 1.方法 sort() 可以对列表永久性排序 ...
- 杭电 5363 求集合的非空子集中key的数量
Description soda has a set S with n integers {1,2,…,n}. A set is called key set if the sum of intege ...
- 2016 Multi-University Training Contest 3-1011.Teacher Bo,暴力!
Teacher Bo Time Limit: 4000/2000 MS (Java/Ot ...
- [luoguP1472] 奶牛家谱 Cow Pedigrees(DP)
传送门 一个深度为i的树可以由一个根节点外加两个深度为i-1的树组成,这就决定了DP该怎么写. 然而我真的没有想到. f[i][j]表示深度为i节点数为j的个数 sum[i][j]表示深度小于等于i节 ...
- DRF:过滤&搜索&排序功能
过滤功能利用的是第三方包 django_filters,搜索和排序利用的是 Django DRF 提供的 filters 示例代码如下: from rest_framework import filt ...
- 乱记结论之OI常用四大数列
一.斐波那契数列 $f(0)=1,f(1)=1,f(i)=f(i-1)+f(i-2) \ \ \ \ (i>=2)$ 经典的解释是兔子生小孩,第0年一对兔子,一对兔子需要一年长大,后面每年都生小 ...
- hash存储结构【六】
一.概述: 我们可以将Redis中的Hashes类型看成具有String Key和String Value的map容器.所以该类型非常适合于存储值对象的信息.如Username.Password和Ag ...
- msp430入门编程11
msp430中C语言的模块化头文件及实现11 msp430中C语言的模块化头文件及库文件12 msp430入门学习 msp430入门编程
- Java DynamoDB 增加、删除、修改、查询
准备jar包 <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sd ...