离散对数(Baby Step Giant Step)

现在我来介绍一种算法叫做Baby Step Giant Step它是用来解决如下方程最小正整数解的


           其中


如果,那么我们可以先取模,即,所以在这里我们只讨论的情况。


普通Baby Step Giant Step的步骤是这样的:

    (1)首先确定的下限是0,上限是,我们令

    (2)把的值存到一个Hash表里面

    (3)把的值一一枚举出来,每枚举一个就在Hash表里面寻找是否有一个值满足

        ,如果有则找到答案,否则继续

    (4)最终答案就是的值对应的原来的幂


     上面是普通Baby Step Giant Step的步骤,比较简单,只适用为素数的情况。如果为合数呢?


为合数时,我们就需要把Baby Step Giant Step扩展一下。在普通Baby Step Giant Step中,由于是素数,那么,所以一定有唯一解的。那么,当为合数时,我们可以这样处理:


对于方程,我们拿出若干个出来与来消去公共因子,使得为止,那么此时我们就可以直接通过扩展欧几里得来计算结果了。



题目:http://www.spoj.com/problems/MOD/


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>

using namespace std;
typedef long long LL;

const int MOD = 99991;
const int N = 100005;

struct Hash
{
    bool f;
    int id;
    int val;
};

Hash hash[N];

void Init()
{
    for(int i=0; i<N; i++)
    {
        hash[i].f = 0;
        hash[i].id = -1;
        hash[i].val = -1;
    }
}

void Insert(int id,LL val)
{
    LL t = val % MOD;
    while(hash[t].f && hash[t].val != val)
    {
        t++;
        t %= MOD;
    }
    if(!hash[t].f)
    {
        hash[t].f = 1;
        hash[t].id = id;
        hash[t].val = val;
    }
}

int Find(LL val)
{
    LL t = val % MOD;
    while(hash[t].f && hash[t].val != val)
    {
        t++;
        t %= MOD;
    }
    if(!hash[t].f) return -1;
    return hash[t].id;
}

LL gcd(LL a,LL b)
{
    return b ? gcd(b,a%b):a;
}

void extend_Euclid(LL a,LL b,LL &x,LL &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    extend_Euclid(b,a%b,x,y);
    LL tmp = x;
    x = y;
    y = tmp - (a / b) * y;
}

LL Baby_Step(LL A,LL B,LL C)
{
    LL ret = 1;
    for(int i=0; i<=50; i++)
    {
        if(ret == B) return i;
        ret = ret * A % C;
    }
    LL ans = 1;
    LL tmp,cnt = 0;
    while((tmp = gcd(A,C)) != 1)
    {
        if(B % tmp) return -1;
        B /= tmp;
        C /= tmp;
        ans = ans * (A / tmp) % C;
        cnt++;
    }
    LL M = ceil(sqrt(1.0*C));
    LL t = 1;
    for(int i=0; i<M; i++)
    {
        Insert(i,t);
        t = t * A % C;
    }
    for(int i=0; i<M; i++)
    {
        LL x,y;
        extend_Euclid(ans,C,x,y);
        LL val = x * B % C;
        val = (val % C + C) % C;
        LL j = Find(val);
        if(j != -1) return i * M + j + cnt;
        ans = ans * t % C;
    }
    return -1;
}

int main()
{
    LL A,B,C;
    while(cin>>A>>C>>B)
    {
        Init();
        if(A + B + C == 0) break;
        A %= C; B %= C;
        LL ans = Baby_Step(A,B,C);
        if(ans == -1)
        {
            puts("No Solution");
            continue;
        }
        cout<<ans<<endl;
    }
    return 0;
}



  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值