高次同余笔记(一):baby-step-giant-step算法
2015-11-17 00:35
441 查看
我们来看这个方程:
a,b,p为常数且在int内。、p是质数。
这个怎么搞?
首先x的取值肯定在0到p-1之间。
暴搜?肯定超时啊。
优化暴搜?用meet-in-the-middle?
先来说说meet-in-the-middle怎么做。
就是找一个点把[0,p-1]这个区间分成两半(一般找中点),算出前一半塞到hash表里面,再算后一半看看hash表里面有没有。
复杂度大概是上面的暴搜的根号。
其实这个思想是好的,它指导我们发现baby-step-giant-step。
先给出baby-step-giant-step算法的步骤。
令m=ceil(sqrt(p)),把(a^0,0),(a^1,1),…,(a^(m-1),m-1)全部塞到hash表里面。
然后令d=a^m,计算d^0,d^1,…,d^m,对于每一个d^i,有
这个东西怎么搞?
用exgcd啊!用exgcd求出来y,然后查询hash表里面有没有y就行了。
如果有y,设对应的指数是k,那么答案就是i*m+k。
如果跑完了都没有,那就无解了。
再回顾这个算法,为什么叫baby-step-giant-step?
因为baby的步长为1,giant的步长为m,然后去凑答案。
这个是什么思想?分块!
把答案分成sqrt(p)块,然后暴力枚举块+解线性同余方程验证块内有无满足题意的解。
有时间再写extend-baby-step-giant-step,这个算法解决了p为合数的状况。或者写写离散对数与原根,它可以解决另一种不同形式的高次同余方程。
附POJ2417BSGS裸题代码(hash表乱写的所以很慢)
a,b,p为常数且在int内。、p是质数。
这个怎么搞?
首先x的取值肯定在0到p-1之间。
暴搜?肯定超时啊。
优化暴搜?用meet-in-the-middle?
先来说说meet-in-the-middle怎么做。
就是找一个点把[0,p-1]这个区间分成两半(一般找中点),算出前一半塞到hash表里面,再算后一半看看hash表里面有没有。
复杂度大概是上面的暴搜的根号。
其实这个思想是好的,它指导我们发现baby-step-giant-step。
先给出baby-step-giant-step算法的步骤。
令m=ceil(sqrt(p)),把(a^0,0),(a^1,1),…,(a^(m-1),m-1)全部塞到hash表里面。
然后令d=a^m,计算d^0,d^1,…,d^m,对于每一个d^i,有
这个东西怎么搞?
用exgcd啊!用exgcd求出来y,然后查询hash表里面有没有y就行了。
如果有y,设对应的指数是k,那么答案就是i*m+k。
如果跑完了都没有,那就无解了。
再回顾这个算法,为什么叫baby-step-giant-step?
因为baby的步长为1,giant的步长为m,然后去凑答案。
这个是什么思想?分块!
把答案分成sqrt(p)块,然后暴力枚举块+解线性同余方程验证块内有无满足题意的解。
有时间再写extend-baby-step-giant-step,这个算法解决了p为合数的状况。或者写写离散对数与原根,它可以解决另一种不同形式的高次同余方程。
附POJ2417BSGS裸题代码(hash表乱写的所以很慢)
[code]#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define ll long long using namespace std; ll a,b,p,hsh[70000][2]; bool ishsh[70000]; void insert(ll x,ll t) { ll p=x*12580%70000; while(ishsh[p])p=(p+1)%70000; ishsh[p]=1; hsh[p][0]=x; hsh[p][1]=t; } int query(ll x) { ll p=x*12580%70000; while(hsh[p][0]!=x&&ishsh[p]) p=(p+1)%70000; if(!ishsh[p])return -1; return hsh[p][1]; } void exgcd(ll a,ll b,ll &d,ll &x,ll &y) { if(!b){x=1;d=a;y=0;} else { exgcd(b,a%b,d,y,x); y-=a/b*x; } } void BSGS() { ll m=ceil(sqrt(p)),d=1,val=1,gcd,x,y,t; for(int i=0;i<m;++i) { insert(val,i); val=val*a%p; } for(int i=0;i<m;++i) { exgcd(d,p,gcd,x,y); x=(b/gcd*x%p+p)%(p/gcd); t=query(x); if(t!=-1){printf("%I64d\n",i*m+t);return;} d=d*val%p; } printf("no solution\n"); } int main() { while(~scanf("%I64d%I64d%I64d",&p,&a,&b)) { memset(hsh,0,sizeof hsh); memset(ishsh,0,sizeof ishsh); BSGS(); } }
相关文章推荐
- windows下实现Git在局域网使用
- hdu3037 Saving Beans
- 数据的导出与导入
- Android中的责任链模式
- LVS集群-DR负载均衡集群
- 学习Python(二)
- 反转字符串
- 宏应用
- Simplexml_load_string函数解析xml
- Installing Ubuntu 14.04 LTS (Trusty Tahir) VM on a XenServer 6.2 host
- C语言编程规范5: 预编译宏
- leetcode: Bulls and Cows
- 值得用一首歌时间来阅读的文章
- xib 自定义 Cell(二)
- java实现队列
- ActiveMQ入门实例 - ActiveMQ教程
- Webkit之多进程分析
- 微服务,ApiGateway 与 Kong
- 开始使用Mac
- IP地址的简单说明---Linux学习笔记