您的位置:首页 > 其它

foj 1493 基础baby-step-giant-step

2012-11-22 19:41 169 查看
首先讲一下基础的baby-step-giant-step,解决的问题模型是求A^x=B(mod C)的解,其中0<=x<C,C为素数。

x=i*m+j (0<=i<m,0<=j<m,m=Ceil(sqrt(C))),问题转变为(A^i)^m*A^j=B(mod C),进一步转换为(A^m)^i*A^j=B(mod C)

求出(A^i)modC的值并储存到hash中(i from 0 to m)

枚举i(from 0 to m),根据扩展欧几里得得到一个解(由于C是素数,在0-C中只存在一个解),然后在hash表里查找是否存在这个解,如果存在则对应一个j,i*m+j就是问题的最小非负解了。

edit: 发现bug,应该对于hash去一下重,这样才能保证二分的结果最小。 2013/3/22

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long llong;
struct baby
{
    llong data;
    int index;
};
bool cmp(baby a,baby b)
{
    return a.data<b.data;
}
baby hash[1<<17];
llong ex_gcd(llong a,llong b,llong& x,llong& y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    else
    {
        llong ans,t;
        ans=ex_gcd(b,a%b,x,y);
        t=x;
        x=y;
        y=t-a/b*y;
        return ans;
    }
}
int bi_search(llong x,int m)
{
    int l,r,mid;
    l=0,r=m,mid=(l+r)>>1;
    while(l<r)
    {
        if(hash[mid].data==x)
            return hash[mid].index;
        else if(hash[mid].data<x)
            l=mid+1;
        else
            r=mid;
        mid=(l+r)>>1;
    }
    return -1;
}
llong quickpow(llong a,llong b,llong c)
{
    llong ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%c;
        a=(a*a)%c;
        b>>=1;
    }
    return ans;
}
llong bsgs(llong a,llong b,llong c)
{
    llong m=llong(sqrt(double(c)))+1;
    llong i,j,t,AA,gcd,x,y,tmp;
    t=1,hash[0].index=0,hash[0].data=1;
    for(i=1;i<m;++i)
    {
        t=(t*a)%c;
        hash[i].data=t;
        hash[i].index=i;
    }
    sort(hash,hash+m,cmp);
    AA=quickpow(a,m,c);
    t=1;
    for(i=0;i<m;++i)
    {
        ex_gcd(t,c,x,y);
        x=(x%c+c)%c;
        x=(x*b)%c;
//        for(j=0;j<m;++j)
//            if(hash[j]==x)
//                return i*m+j; //超时 
        j=bi_search(x,m);
        if(j!=-1)
            return i*m+j;
        t=(t*AA)%c;
    }
    return -1;
}
int main()
{
    llong p,g,y,ans;
    while(scanf("%I64d %I64d %I64d",&p,&g,&y)!=EOF)  
    {
        ans=bsgs(g,y,p);
        if(ans==-1)
            printf("ERROR\n");
        else
            printf("%I64d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: