您的位置:首页 > 其它

离散对数(Baby Step Giant Step)

2013-02-12 20:04 411 查看
现在我来介绍一种算法叫做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
;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: