poj 2417 Discrete Logging(求离散对数)

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值