0
点赞
收藏
分享

微信扫一扫

离散对数(Baby Step Giant Step)


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


       

离散对数(Baby Step Giant Step)_取模

    其中

离散对数(Baby Step Giant Step)_#include_02


如果

离散对数(Baby Step Giant Step)_#include_03

,那么我们可以先取模,即

离散对数(Baby Step Giant Step)_取模_04

,所以在这里我们只讨论

离散对数(Baby Step Giant Step)_取模_05

的情况。


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

    (1)首先确定

离散对数(Baby Step Giant Step)_取模_06

的下限是0,上限是

离散对数(Baby Step Giant Step)_i++_07

,我们令

离散对数(Baby Step Giant Step)_i++_08

    (2)把

离散对数(Baby Step Giant Step)_取模_09

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

离散对数(Baby Step Giant Step)_i++_10

的值一一枚举出来,每枚举一个就在Hash表里面寻找是否有一个值

离散对数(Baby Step Giant Step)_i++_11

满足        

离散对数(Baby Step Giant Step)_i++_12

,如果有则找到答案,否则继续    (4)最终答案就是

离散对数(Baby Step Giant Step)_i++_13

的值对应的原来

离散对数(Baby Step Giant Step)_#include_14

的幂


普通Baby Step Giant Step的步骤,比较简单,只适用

离散对数(Baby Step Giant Step)_i++_07

为素数的情况。如果

离散对数(Baby Step Giant Step)_i++_07

为合数呢?



离散对数(Baby Step Giant Step)_i++_07

为合数时,我们就需要把Baby Step Giant Step扩展一下。在普通Baby Step Giant Step中,由于

离散对数(Baby Step Giant Step)_i++_07

是素数,那么

离散对数(Baby Step Giant Step)_#include_19

,所以

离散对数(Baby Step Giant Step)_取模_20

一定有唯一解的。那么,当

离散对数(Baby Step Giant Step)_i++_07

为合数时,我们可以这样处理:


对于方程

离散对数(Baby Step Giant Step)_#include_22

,我们拿出若干个

离散对数(Baby Step Giant Step)_i++_23

出来与

离散对数(Baby Step Giant Step)_i++_07

来消去公共因子,使得

离散对数(Baby Step Giant Step)_#include_19

为止,那么此时我们就可以直接通过扩展欧几里得来计算结果了。



题目: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 条评论