bsgs(Baby Steps Giant Steps)算法

BSGS算法(Baby Steps Giant Steps算法,大步小步算法,北上广深算法,拔山盖世算法)

适用问题

对于式子:

$$x^y=z(mod_p)$$

已知x,z,p,p为质数;

求解一个最小非负整数y;



存在一个y,属于[0,p-2](费马小定理)

于是有了一个笨拙的方法,枚举y

枚举y,期望效率:O(P)

寻求一种优化:

对式子变型:

设:$$y=i\sqrt{p}-j$$

则$$x^{i\sqrt{p}-j}=z(mod_p)$$

——这个变型的用意在于把y拆开

枚举y,变成枚举,i,j;

i在1~$\sqrt{p}$之间,j在0~$\sqrt{p}$之间

(根号上取整,其实i,j的范围大可大些——只要保证y不会小于0)

枚举(i,j),期望效率:$O(\sqrt{p}*\sqrt{}p)$

本质上没有优化

接着变型:

$$x^{i\sqrt{p}}=z*x^{j}(mod_p)$$ 

——这个变型的用意在于真正把y分离为两部分

枚举j,把等号右边的模后得数置于hash_table,此时同一个得数只留最大的j值;

从小到大枚举i,计算等号左边的模后得数,查询hash_table,第一个成功查询的i,与其相应的j,组成$i\sqrt{p}-j$即为最小的y,

期望效率:$O(\sqrt{p}*T(hash))$

效率优异,拔山盖世的bsgs算法,就是这样了;



 

例题:

[SDOI2011]计算器

代码:

#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
const int ss=999983; 
using namespace std;
int hash_tab[1000000],tot;
struct ss{
    int nu,next,j;
}data[1000000];
void work();
void work1();
void work2();
void work3();
LL Sqr(LL ,int );
int hash(int, int ,int );
LL z,y,p;
bool flag;
int main()
{
    work();
}
void work(){
    int T,K;
    scanf("%d%d",&T,&K);
    while(T--){
        scanf("%lld%lld%lld",&y,&z,&p);
        if(K==1)
            work1();
        if(K==2)
            work2();
        if(K==3)
            work3();
    }
}
void work1(){
    int i,j,k;
    printf("%lld\n",Sqr(y,z));
}
void work2(){
    int ans,less;
    if((!(y%p)&&z)||((y%p)&&!z)){
        printf("Orz, I cannot find x!\n");return;
    }
    printf("%lld\n",Sqr(y%p,p-2)*z%p);
}
void work3(){
    long long ysqrtp,sqrtp=ceil(sqrt(p));
    memset(hash_tab,0,sizeof(hash_tab));
    memset(data,0,sizeof(data));
    long long l=1,r=z%p;
    int i,j;
    if((!(y%p)&&z)||((y%p)&&!z)){
        printf("Orz, I cannot find x!\n");return;
    }
    ysqrtp=Sqr(y,sqrtp);
    for(i=0;i<=sqrtp;i++)
        hash(r,i,0),(r*=y)%=p;
    for(i=1;i<=sqrtp;i++){
        (l*=ysqrtp)%=p;
        if((j=hash(l,0,1))!=-1){
            printf("%lld\n",i*sqrtp-j);
            return ;
        }
    }
    printf("Orz, I cannot find x!\n");
}
LL Sqr(LL x,int n){
    LL ret=1;
    while(n){
        if(n&1)(ret*=x)%=p;
        (x*=x)%=p;n>>=1;
    }
    return ret;
}
int hash(int num,int j,int flag){
    int tem;
    for(tem=hash_tab[num%ss];tem;tem=data[tem].next){
        if(data[tem].nu==num){
            if(!flag&&j>data[tem].j)
                data[tem].j=j;
            return data[tem].j;
        }
        if(!data[tem].next&&!flag){
            data[tem].next=++tot;
            data[tot].j=j;
            data[tot].nu=num;
            return -1;
        }
    }
    if(!flag){
        hash_tab[num%ss]=++tot;
        data[tot].j=j;
        data[tot].nu=num;
    }
    return -1;
}
View Code

 

posted @ 2017-09-08 11:39  F.W.Nietzsche  阅读(293)  评论(0编辑  收藏  举报