Discrete Logging

本文介绍了一种解决离散对数问题的方法,并通过Baby Step Giant Step算法实现。该算法利用哈希表来提高计算效率,对于特定的输入参数(素数P、底数B及目标N),能够找到最小的整数L,使得B的L次方模P等于N。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目地址请点击——


Discrete Logging


Description

Given a prime P , 2P<231 , an integer B , 2B<P , and an integer N , 1N<P , compute the discrete logarithm of N , base B , modulo P .
That is , find an integer L such that

BLN (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 states

BP11 (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

BmBP1m (mod P)
.


Source

Waterloo Local 2002.01.26


Solution

Baby Step Giant Step 算法的模板题。


Code

#include <iostream>
#include <cstdio>
#include <cmath>

#define LL long long
#define HASH_MOD 786433

using namespace std;

LL p,b,n,ans;
LL fx,fy;

struct map{
    LL h[800000],v[800000],nxt[800000],ne[800000];
    void clear(){
        memset(nxt,-1,sizeof nxt);
        memset(h,-1,sizeof h);
        ne[786433]=0;
        for(LL i=0;i<786433;i++)ne[i]=i;
    }
    LL fi(LL x){
        LL tmp=x,pre;
        while(tmp!=ne[tmp])tmp=ne[tmp];
        while(x!=tmp){pre=ne[x];ne[x]=tmp;x=pre;}
        return tmp;
    }
    void insert(LL x,LL y){
        LL mx=x%HASH_MOD;
        while(nxt[mx]!=-1)
            mx=nxt[mx];
        nxt[mx]=fi(0);
        ne[nxt[mx]]=ne[nxt[mx]]+1;
        h[nxt[mx]]=x;
        v[nxt[mx]]=y;
    }
    LL find(LL x){
        LL mx=x%HASH_MOD;
        while(x!=h[mx]&&nxt[mx]!=-1)mx=nxt[mx];
        if(x!=h[mx])return -1;
        return v[mx];
    }
};

map hash;

LL power(LL x,LL y,LL Mod){
    x%=Mod;
    LL ans=1;
    while(y){
        if(y&1)ans=ans*x%Mod;
        x=x*x%Mod;
        y>>=1;
    }
    return ans;
}

LL ex_gcd(LL x,LL y,LL &a,LL &b){
    if(y==0){a=1;b=0;return x;}
    LL fa,fb;
    LL c=ex_gcd(y,x%y,fa,fb);
    a=fb;
    b=fa-fb*(x/y);
    return c;
}

int main(){

    while(scanf("%lld%lld%lld",&p,&b,&n)!=EOF){

        b%=p;n%=p;

        hash.clear();
        LL MAXN=ceil(sqrt((double)p));
        bool flag=false;
        for(LL i=0;i<MAXN;i++){
            LL tmp=power(b,i,p);
            if(tmp==n){printf("%lld\n",i);flag=true;break;}
            hash.insert(tmp,i);
        }
        if(flag)continue;

        LL QMM=power(b,MAXN,p);
        if(QMM==n){printf("%lld\n",MAXN);goto nxt;}
        ex_gcd(QMM,p,fx,fy);
        fx=(fx*n%p+p)%p;
        if((ans=hash.find(fx))!=-1){printf("%lld\n",ans+MAXN);goto nxt;}

        for(LL i=2;i<=MAXN;i++){
            LL tmp=power(QMM,i,p);
            ex_gcd(tmp,p,fx,fy);
            fx=(fx*n%p+p)%p;
            if((ans=hash.find(fx))!=-1){printf("%lld\n",ans+MAXN*i);goto nxt;}
        }

        printf("no solution\n");

        nxt:;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值