poj 2417 小步大步演算法+費馬小定理求逆元
阿新 • • 發佈:2018-12-24
/*小步大步演算法+費馬小定理求逆元 如果p為素數,a為整數,則a^(p-1)=1(mod p) -> a^(p-2)=(a^(-1))(mod p),又想了下,這個條件成立要a<p;那麼一開始取模就行了。 Baby-Steps-Giant-Steps演算法 高次同餘方程。 A^x== B (mod C) 這裡用到baby_step,giant_step演算法。意為先小步,後大步。 令x=i*m+j (m=ceil(sqrt(p))), 那麼原式化為 A^(i*m)*A^j==B(MOD C) ————> A^j===B*A^(-i*m)(MOD C) 我們先預處理A^0,A^1,A^2……A^(m-1),存入HASH表。,這一步就是baby-step,每次移動1 然後求出A^-m,列舉i,如果存在A^(-i*m)存在於HASH表中,說明存在解x=i*m+j ,這一步為giant_step,每次移動m 至於B^(-m)的求法,可以先求出B的逆元,也就是B^-1。 注意以上解法是最基本的,只能對於C為素數 */ //資料比較大,凡是有相乘的地方都要注意溢位
//Accepted 4608K 4032MS G++ 1365B 莫名通過 #include<cstdio> #include<iostream> #include<map> #include<cmath> #include<set> #define ll long long using namespace std; ll C,A,B; ll fast_pow(ll a,ll b){ //求解(a^b)%C的值 ll ans=1; while(b){ if(b&1) ans=(ans*a)%C; b>>=1; a=(a*a)%C; } return ans; } int main(){ while(~scanf("%lld%lld%lld",&C,&A,&B)){ int m=(int)ceil(sqrt(C)); map<int,int> hash; set<int> vis; map<int,int>::iterator it,end=hash.end(); for(int i=0;i<m;i++) { //此操作時間複雜度到了m*logm,打表 int p=fast_pow(A,i); //it=hash.find(p); if(vis.count(p)==0){ vis.insert(p); hash[p]=i; } } int t=fast_pow(fast_pow(A,C-2),m);//先求逆元A^(-1),再求A^(-i*m) ll tt=B; ll ans=-1; for(int i=0;i<m;i++)//列舉i { // if(vis.count(tt)) { //it=hash.find(tt); ans=m*i+hash[tt]; break; } tt=(tt*t)%C; } if(ans==-1) puts("no solution"); else printf("%lld\n",ans); } return 0; }
//莫名加速 Accepted 5628K 2454MS G++ #include<cstdio> #include<iostream> #include<map> #include<cmath> #include<set> #define ll long long using namespace std; ll C,A,B; ll fast_pow(ll a,ll b){ //求解(a^b)%C的值 ll ans=1; while(b){ if(b&1) ans=(ans*a)%C; b>>=1; a=(a*a)%C; } return ans; } int main(){ while(~scanf("%lld%lld%lld",&C,&A,&B)){ int m=(int)ceil(sqrt(C)); map<int,int> hash; map<int,bool> vis; map<int,int>::iterator it,end=hash.end(); for(int i=0;i<m;i++) { //此操作時間複雜度到了m*logm,打表 int p=fast_pow(A,i); //it=hash.find(p); if(vis[p]==0){ vis[p]=1; hash[p]=i; } } int t=fast_pow(fast_pow(A,C-2),m);//先求逆元A^(-1),再求A^(-i*m) ll tt=B; ll ans=-1; for(int i=0;i<m;i++)//列舉i { if(vis[tt]) { //it=hash.find(tt); ans=m*i+hash[tt]; break; } tt=(tt*t)%C; } if(ans==-1) puts("no solution"); else printf("%lld\n",ans); } return 0; }
//莫名超時
#include<cstdio>
#include<iostream>
#include<map>
#include<cmath>
#define ll long long
using namespace std;
ll C,A,B;
ll fast_pow(ll a,ll b){
//求解(a^b)%C的值
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%C;
b>>=1;
a=(a*a)%C;
}
return ans;
}
int main(){
while(~scanf("%lld%lld%lld",&C,&A,&B)){
int m=(int)ceil(sqrt(C));
map<int,int> hash;
map<int,int>::iterator it,end=hash.end();
for(int i=0;i<m;i++)
{
//此操作時間複雜度到了m*logm,打表
int p=fast_pow(A,i);
it=hash.find(p);
if(it==end) hash[p]=i;
}
int t=fast_pow(fast_pow(A,C-2),m);//先求逆元A^(-1),再求A^(-i*m)
ll tt=B;
ll ans=-1;
for(int i=0;i<m;i++)//列舉i
{
it=hash.find(tt);
if(it!=end)
{
ans=m*i+it->second;
break;
}
tt=(tt*t)%C;
}
if(ans==-1)
puts("no solution");
else
printf("%lld\n",ans);
}
return 0;
}
//莫名超時
#include<cstdio>
#include<iostream>
#include<map>
#include<cmath>
#define ll long long
using namespace std;
ll C,A,B;
ll fast_pow(ll a,ll b){
//求解(a^b)%C的值
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%C;
b>>=1;
a=(a*a)%C;
}
return ans;
}
int main(){
while(~scanf("%lld%lld%lld",&C,&A,&B)){
int m=(int)ceil(sqrt(C));
map<int,int> hash;
map<int,int>::iterator it,end=hash.end();
for(int i=0;i<m;i++)
{
//此操作時間複雜度到了m*logm,打表
int p=fast_pow(A,i);
if(hash.count(p)==0) hash[p]=i;
}
int t=fast_pow(fast_pow(A,C-2),m);//先求逆元A^(-1),再求A^(-i*m)
ll tt=B;
ll ans=-1;
for(int i=0;i<m;i++)//列舉i
{
if(hash.count(tt))
{
ans=m*i+hash[tt];
break;
}
tt=(tt*t)%C;
}
if(ans==-1)
puts("no solution");
else
printf("%lld\n",ans);
}
return 0;
}
Discrete Logging
Time Limit: 5000MS | Memory Limit: 65536K |
Total Submissions: 5835 | Accepted: 2604 |
Description
Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarithm of N, base B, modulo P. That is, find an integer L such thatBL == N (mod P)
Input
Read several lines of input, each containing P,B,N separated by a space.Output
For each line print the logarithm on a separate line. If there are several, print the smallest; if there is none, print "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
Hint
The solution to this problem requires a well known result in number theory that is probably expected of you for Putnam but not ACM competitions. It is Fermat's theorem that statesB(P-1) == 1 (mod P)
for any prime P and some other (fairly rare) numbers known as base-B pseudoprimes. A rarer subset of the base-B pseudoprimes, known as Carmichael numbers, are pseudoprimes for every base between 2 and P-1. A corollary to Fermat's theorem is that for any m
B(-m) == B(P-1-m) (mod P) .用排序+二分查詢,效率會提高10倍,因為本來陣列就基本有序,所以排序的效率就高了,所以說還是不能剛看時間複雜度,還是要具體問題具體分析。