BSGS算法及扩展

BSGS算法

BabyStepGiantStep B a b y S t e p G i a n t S t e p 算法,即大步小步算法,缩写为 BSGS B S G S
拔山盖世算法

它是用来解决这样一类问题
yx=z(mod p) y x = z ( m o d   p ) ,给定 y,z,p>=1 y , z , p >= 1 求解 x x

普通的BSGS只能用来解决 gcd(y,p)=1 g c d ( y , p ) = 1 的情况

x=am+b,m=p,a[0,m),b[0,m) x = a ∗ m + b , m = ⌈ p ⌉ , a ∈ [ 0 , m ) , b ∈ [ 0 , m )
那么 yam=zyb(mod p) y a ∗ m = z ∗ y − b ( m o d   p )

怎么求解,为了方便,设 x=amb x = a ∗ m − b
那么 yam=zyb(mod p),a(0,m+1] y a ∗ m = z ∗ y b ( m o d   p ) , a ∈ ( 0 , m + 1 ]

直接暴力辣,把右边的 b b 枚举[0,m),算出 zyb(mod p) z ∗ y b ( m o d   p ) ,哈希存起来
然后左边 a a 枚举(0,m+1],算出 yam(mod p) y a ∗ m ( m o d   p ) 查表就行了

然后不知道为什么要用 exgcd e x g c d ,只会 map m a p

代码

[SDOI2011]计算器

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

template <class Int>
IL void Input(RG Int &x){
    RG int z = 1; RG char c = getchar(); x = 0;
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    x *= z;
}

IL void None(){
    puts("Orz, I cannot find x!");
}

int p;

IL int Pow(RG ll x, RG ll y){
    RG ll ret = 1;
    for(; y; x = x * x % p, y >>= 1)
        if(y & 1) ret = ret * x % p;
    return ret;
}

map <int, int> pw;

IL void BSGS(RG int x, RG int y){
    pw.clear();
    if(y == 1){
        puts("0");
        return;
    }
    RG int ans = -1, m = sqrt(p) + 1, xx, s = y;
    for(RG int i = 0; i < m; ++i){
        pw[s] = i;
        s = 1LL * s * x % p;
    }
    xx = Pow(x, m), s = 1;
    for(RG int i = 1; i <= m + 1; ++i){
        s = 1LL * s * xx % p;
        if(pw.count(s)){
            ans = i * m - pw[s];
            break;
        }
    }
    if(ans < 0) None();
    else printf("%d\n", ans);
}

int T, k, y, z;

int main(RG int argc, RG char* argv[]){
    for(Input(T), Input(k); T; --T){
        Input(y), Input(z), Input(p);
        if(k == 1) printf("%d\n", Pow(y, z));
        else if(k == 2){
            RG int d = (y % p) ? 1 : p;
            if(z % d) None();
            else printf("%lld\n", 1LL * Pow(y, p - 2) * z % p);
        }
        else{
            if(y % p) BSGS(y % p, z % p);
            else None();
        }
    }
    return 0;
}

扩展BSGS

对于 gcd(y,p)1 g c d ( y , p ) ≠ 1 怎么办?

我们把它写成 yyx1+kp=z,kZ y ∗ y x − 1 + k ∗ p = z , k ∈ Z 的形式

根据 exgcd e x g c d 的理论
那么如果 y,p y , p gcd g c d 不是 z z 的约数就不会有解

d=gcd(y,p)
那么

ydyx1+kpd=zd y d ∗ y x − 1 + k ∗ p d = z d

递归到 d=1 d = 1
设之间的所有的 d d 的乘积为g,递归 c c
x=xc,p=pg,z=zg
那么

yxycg=z(mod p) y x ′ ∗ y c g = z ′ ( m o d   p ′ )

那么 BSGS B S G S 求解就好了

代码

SPOJMOD Power Modulo Inverted

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
# define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
using namespace std;
typedef long long ll;

template <class Int>
IL void Input(RG Int &x){
    RG int z = 1; RG char c = getchar(); x = 0;
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    x *= z;
}

map <int, int> pw;

IL int Gcd(RG int x, RG int y){
    return !y ? x : Gcd(y, x % y);
}

IL int Pow(RG ll x, RG ll y, RG int p){
    RG ll ret = 1;
    for(; y; x = x * x % p, y >>= 1)
        if(y & 1) ret = ret * x % p;
    return ret;
}

int a, b, p;

IL int EX_BSGS(){
    if(b == 1) return 0;
    pw.clear();
    RG int cnt = 0, t = 1, s, x, m;
    for(RG int d = Gcd(a, p); d != 1; d = Gcd(a, p)){
        if(b % d) return -1;
        ++cnt, b /= d, p /= d, t = 1LL * t * a / d % p;
        if(b == t) return cnt;
    }
    s = b, m = sqrt(p) + 1;
    for(RG int i = 0; i < m; ++i){
        pw[s] = i;
        s = 1LL * s * a % p;
    }
    x = Pow(a, m, p), s = t;
    for(RG int i = 1; i <= m; ++i){
        s = 1LL * s * x % p;
        if(pw.count(s)) return i * m - pw[s] + cnt;
    }
    return -1;
}

int ans;

int main(RG int argc, RG char* argv[]){
    for(Input(a), Input(p), Input(b); a + b + p;){
        a %= p, b %= p, ans = EX_BSGS();
        if(ans < 0) puts("No Solution");
        else printf("%d\n", ans);
        Input(a), Input(p), Input(b);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值