Discrete Logging
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 3464 | Accepted: 1622 |
Description
Given a prime P, 2 <= P < 2
31, 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 that
BL == 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
题意:求离散对数问题
题解:用baby step gaint step 算法+hash,具体是,由于当x等于p-1时,就会循环,所以x必定小于p,然后,先将p其分成m=sqrt(p)个区间,那么对于第一个区间b的0、1、……、m-1次方,依次求出来并保存,判断是否满足条件,这里x的次幂每次加1;然后根据恒等式 b^x*b^m≡k(mod p)等价于b^x≡k*b^(-m) (mod p),那么依次将k乘以b^(-m) (这里的b^(-m)是b的m次方对于p的逆模),乘i个b^(-m)则相对等价于判断b^(im)+0、b^(im)+1、……、b^(im+m-1)是否满足条件,详细如代码
#include<stdio.h>
#include<string.h>
#include<math.h>
#define maxn 65535
typedef long long LL;
LL head[maxn+520],all;
struct Hash{
LL a,b,next;
}has[maxn<<1];
LL pow_mod(LL a,LL m,LL mod)
{
LL res=1;
while(m)
{
if(m&1) res=((long long)res*a)%mod;
a=((long long)a*a)%mod;
m=m>>1;
}
return res;
}
void exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b){ x=1; y=0; }
else{ exgcd(b,a%b,y,x); y-=x*(a/b); }
}
void myinsert(LL e,LL i)
{
LL k=e&maxn;
if(head[k]==-1)
{
head[k]=++all;
has[all].b=e;
has[all].a=i;
has[all].next=-1;
}
else
{
k=head[k];
while(has[k].next!=-1)
{
if(has[k].b==e) return;
k=has[k].next;
}
has[k].next=++all;
has[all].b=e;
has[all].a=i;
has[all].next=-1;
}
}
LL myfind(LL b)
{
int k=b&maxn;
if(head[k]==-1) return -1;
k=head[k];
while(k!=-1)
{
if(has[k].b==b) return has[k].a;
k=has[k].next;
}
return -1;
}
LL inv(LL a,LL mod)
{
LL x,y;
exgcd(a,mod,x,y);
return (x%mod+mod)%mod;
}
LL solve(LL a,LL b,LL mod)
{
LL m=(LL)sqrt(mod+0.5);
LL e=1,v=inv(pow_mod(a,m,mod),mod);
memset(head,-1,sizeof(head));
all=0;
for(LL i=0;i<=m;i++)
{
myinsert(e,i);
e=((long long)e*a)%mod;
}
for(LL i=0;i<m;i++)
{
LL temp=myfind(b);
if(temp!=-1) return i*m+temp;
b=(((long long)b*v)%mod+mod)%mod;
}
return -1;
}
int main()
{
LL p,b,n;
while(scanf("%I64d%I64d%I64d",&p,&b,&n)>0)
{
LL res=solve(b,n%p,p);
if(res==-1) printf("no solution\n");
else printf("%I64d\n",res);
}
return 0;
}