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;
}

时间: 2024-10-30 18:37:59

bsgs(Baby Steps Giant Steps)算法的相关文章

BSGS算法_Baby steps giant steps算法(无扩展)最强详解,你从未见过的详细

Baby Steps-Varsity Giant Step-Astronauts(May'n?椎名慶治) 阅读时可以听听这两首歌,加深对这个算法的理解.(Baby steps少女时代翻唱过,这个原唱反而不是很有名……Giant Step就比较碉,是一个假面骑士片的插曲,由超碉的May'n和一个人建立的临时组合唱的,怕不怕) 这个主要是用来解决这个题: A^x=B(mod C)(C是质数),都是整数,已知A.B.C求x. 我在网上看了好多介绍,觉得他们写得都不够碉,我看不懂…于是我也来写一发. 先

HDU 2815 扩展baby step giant step 算法

题目大意就是求 a^x = b(mod c) 中的x 用一般的baby step giant step 算法会超时 这里参考的是http://hi.baidu.com/aekdycoin/item/236937318413c680c2cf29d4 map平衡树查找值 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <cmath> 5 #include <

HDU 2815 Mod Tree 离散对数 扩展Baby Step Giant Step算法

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2815 题意: 思路:与上题不同,这道题不要求m是素数,是利用扩展Baby Step Giant Step算法求离散对数. 以下转载自:AekdyCoin [扩展Baby Step Giant Step] [问题模型] 求解 A^x = B (mod C) 中 0 <= x < C 的解,C 无限制(当然大小有限制--) [写在前面] 这个问题比较麻烦,目前网络上流传许多版本的做法,不过大部分已近被证明

BSGS(Baby Steps,Giant Steps)

#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,m,y,z,p,x,ans,block; map<ll,int>mp; ll quick(ll a,ll b,ll p) { ll res=1%p; while (b) { if (b&1) { res=res*a%p; } a=a*a%p; b=b>>1; } return res; } void solve1() {

BSGS_Baby steps giant steps算法

BSGS这个主要是用来解决这个题: A^x=B(mod C)(C是质数),都是整数,已知A.B.C求x. 在具体的题目中,C一般是所有可能事件的总数. 解: 设m = ceil(sqrt(C))(ceil为上取整), x = i * m + j, 那么A^x = (A^m)^i * A^j, (0 <= i < m, 0 <= j < m). 然后可以枚举i,O(sqrt(C))级别的枚举. 对于一个枚举出来的i,令D = (A^m)^i现在问题转化为求D * A^j ≡ B (m

数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)

什么叫高次同余方程?说白了就是解决这样一个问题: A^x=B(mod C),求最小的x值. baby step giant step算法 题目条件:C是素数(事实上,A与C互质就可以.为什么?在BSGS算法中是要求a^m在%c条件下的逆元的,如果a.c不互质根本就没有逆元.) 如果x有解,那么0<=x<C,为什么? 我们可以回忆一下欧拉定理: 对于c是素数的情况,φ(c)=c-1 那么既然我们知道a^0=1,a^φ(c)=1(在%c的条件下).那么0~φ(c)必定是一个循环节(不一定是最小的)

POJ 2417 Discrete Logging ( Baby step giant step )

Discrete Logging Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3696   Accepted: 1727 Description Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarithm of N, b

【poj2417】baby step giant step

最近在学习数论,然而发现之前学的baby step giant step又忘了,于是去翻了翻以前的代码,又复习了一下. 觉得总是忘记是因为没有彻底理解啊. 注意baby step giant step只能用在b和p互质的情况下,因为只有b和p互质的情况下,b才有mod p下的逆元.(下面要用到逆元) 当b和p不互质,就要处理一下.现在就正在做这么一题,方法以后再写. 求a^(-m)就用到了求逆元了,那么如何求逆元呢?我学了两种方法: ·1:欧拉定理:当a和n互质,a^φ ( n) ≡ 1(mod

BSGS(大小步)算法

BSGS算法主要用于求解形如ax≡b(mod p)的式子中x的值. 在这里我们不妨设 x=k1*n-k2 这时我们就可以将式子转化为 ak1*n≡b*ak2(mod p) 这里的n我们设为√p,所以我们利用分块的思想在块数范围内枚举k1即可.那在考虑完k1和n之后我们再考虑一下如何找到k2,我们建立一个哈希表,将k2取0~n时的式子左边的值模p然后将其映射到此时k2的取值.求最后答案时我们只需找到在k1最小时满足条件的最大的k2即可. 模板(poj2417) #include<iostream>