POJ 2417 Discrete Logging(高次同余方程-Baby-Step,Giant-Step)
2015-08-26 17:21
148 查看
Description
给出P,B,N(P是素数),解方程B^L = N (mod P)
Input
多组输入,每组用例占一行包括三个整数P,B,N,以文件为结束输入
Output
对于每组用例,如果方程有解则输出最小解,否则输出no solution
Sample Input
5 2 1
5 2 2
5 2 3
5 2 4
5 3 1
5 3 2
5 3 3
5 3 4
5 4 1
5 4 2
5 4 3
5 4 4
12345701 2 1111111
1111111121 65537 1111111111
Sample Output
0
1
3
2
0
3
1
2
0
no solution
no solution
1
9584351
462803587
Solution
解高次同余方程a^x=b(mod p),由于数据范围太大所以暴力显然不行,此处因为b,p互素所以可以采用Baby-Step,Giant-Step算法,令n=sqrt(p),则x可以表示成k*n+r的形式(0 <= k,r <= n),原方程即可转化为a^(k*n+r)=b(mod p),即为a^r=b*(a^(-n))^k(mod p),这样一来我们只需要用O(n)的时间将a^i(0 <= i <= r)预处理从出来存到一个map中,再用O(n)的时间枚举k(先算出a^(-n),此处需要用到费马小定理求逆元),对于每个k用O(log n)的时间在map中查找即可,所以总复杂度是O(n+nlog n),即O(sqrt(p)log(sqrt(p)))
Code
给出P,B,N(P是素数),解方程B^L = N (mod P)
Input
多组输入,每组用例占一行包括三个整数P,B,N,以文件为结束输入
Output
对于每组用例,如果方程有解则输出最小解,否则输出no solution
Sample Input
5 2 1
5 2 2
5 2 3
5 2 4
5 3 1
5 3 2
5 3 3
5 3 4
5 4 1
5 4 2
5 4 3
5 4 4
12345701 2 1111111
1111111121 65537 1111111111
Sample Output
0
1
3
2
0
3
1
2
0
no solution
no solution
1
9584351
462803587
Solution
解高次同余方程a^x=b(mod p),由于数据范围太大所以暴力显然不行,此处因为b,p互素所以可以采用Baby-Step,Giant-Step算法,令n=sqrt(p),则x可以表示成k*n+r的形式(0 <= k,r <= n),原方程即可转化为a^(k*n+r)=b(mod p),即为a^r=b*(a^(-n))^k(mod p),这样一来我们只需要用O(n)的时间将a^i(0 <= i <= r)预处理从出来存到一个map中,再用O(n)的时间枚举k(先算出a^(-n),此处需要用到费马小定理求逆元),对于每个k用O(log n)的时间在map中查找即可,所以总复杂度是O(n+nlog n),即O(sqrt(p)log(sqrt(p)))
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<map> #include<vector> using namespace std; typedef long long ll; ll mod_pow(ll a,ll b,ll p)//快速幂 { ll ans=1; a%=p; while(b) { if(b&1) ans=(ans*a)%p; a=a*a%p; b>>=1; } return ans; } ll mul_linear(ll a,ll b,ll p)//求解高次同余方程a^x=b(mod p) { ll n=ceil(sqrt((double)(p+1))); map<ll,ll>Map; Map[1]=n;//本来a^r=1映射的r值是0,但为便于后面通过Map[x]=0?来判断x是否在Map中所以此处用n代替 ll m=mod_pow(a,p-2,p);//求a的逆元 m=mod_pow(m,n,p);//求a^(-n) ll temp=1; for(ll i=1;i<n;i++)//将a^i存入map中 { temp=(temp*a)%p; if(!Map[temp]) Map[temp]=i; } for(ll i=0;i<n;i++)//枚举k寻找可行解 { if(Map[b]) { ll r=Map[b]; Map.clear(); return i*n+(r==n?0:r);//如果是n表示r=0 } b=(b*m)%p; } return -1;//无解 } int main() { ll B,N,P; while(~scanf("%lld%lld%lld",&P,&B,&N)) { ll ans=mul_linear(B,N,P); if(ans==-1) printf("no solution\n"); else printf("%lld\n",ans); } return 0; }
相关文章推荐
- Android基础总结——进程优先级及提高优先级的方法(Service尽量不死之法)
- BZOJ 3107 CQOI2013 二进制a+b 构造
- 异常总结二
- [LeedCode OJ]#59 Spiral Matrix II
- 面试题9
- JSON与JSONP
- CSS简单导航栏
- 恒生电子2012实习笔试题
- 转载分享:Android APP二次打包操作步骤介绍
- test 2.1-4
- Block
- 数组去重
- POJ3070 - Fibonacci (矩阵快速幂)
- 11111
- HoughLinesP函数(概率检测直线)
- 监督算法大比拼之BP、SVM、adaboost非线性多分类实验
- android执行移动动画后按钮点击错位问题解决
- 数据结构:胜者树与败者树
- Python sys.path.append
- 【使用JSOUP实现网络爬虫】使用DOM方法来遍历一个文档