BSGS & EXBSGS简要

2 篇文章 0 订阅
1 篇文章 0 订阅

原址:https://www.cnblogs.com/sdzwyq/p/9900650.html

BSGS

BSGS主要用于求解形如 x k = y ( m o d p ) x^k=y\pmod p xk=y(modp)(注意这里p和x互质)这样的方程的最小正整数解得问题
m = ⌈ p ⌉ , k = a m − b , a ∈ [ 1 , m ] , b ∈ [ 0 , m ) m=\lceil\sqrt p\rceil,k=am-b,a\in[1,m],b\in[0,m) m=p ,k=amb,a[1,m],b[0,m)那么上面的方程可以变形成 x a m = y x b ( m o d p ) x^{am}=yx^b\pmod p xam=yxb(modp)
枚举b,计算出右边的值存到map中,枚举a查表即可
Q:可以枚举左边存表,右边查嘛?
A:可以,但是左边查到表可以直接输出…
顺便一说,map里要存最大值,这样你算出的答案是最小的,所以能更新就更新
复杂度: O ( p l o g p ) O(\sqrt plogp) O(p logp)
模板题[TJOI2007]可爱的质数

#include <bits/stdc++.h>
using namespace std;
template <class T> void read(T &x) {
    x = 0; bool f = 0; char ch = getchar();
    while (!(ch >= '0' && ch <= '9')) {if (ch == '-') f = 1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    if (f) x = -x;
}
template <class T> void write(T x) {
    if (x < 0) x = -x, putchar('-');
    if (x / 10) write(x / 10);
    putchar('0' + x % 10);
}
int MOD;
int ksm(int a, int b) {int ret = 1; for (; b; b >>= 1, a = 1ll * a * a % MOD) if (b & 1) ret = 1ll * ret * a % MOD; return ret;}
map<int, int> mp;
int main() {
    int x, y; read(MOD), read(x), read(y);
    int m = sqrt(MOD) + 1, s = y;
    for (int i = 0; i < m; i++) {mp[s] = i; s = 1ll * s * x % MOD;}
    int t = ksm(x, m); s = 1;
    for (int i = 1; i <= m; i++) {
        s = 1ll * s * t % MOD;
        if (mp[s]) {write(i * m - mp[s]); return 0;}
    }
    puts("no solution");

    return 0;
}

扩展BSGS

当p不是素数时(这时x,p不一定互质),
设d=gcd(x,p),
若d不整除y,那么只有y=1时,x=0,其他情况均无解
若d整除y,当d=1时,直接BSGS
否则有
x k = y ( m o d p ) x^k=y\pmod p xk=y(modp)
x k − 1 × x d = y d ( m o d p d ) x^{k-1}×\frac{x}{d}=\frac{y}{d}\pmod{\frac{p}{d}} xk1×dx=dy(moddp)
继续分解到d=1为止.
x k − t × x t ∏ d i = y ∏ d i ( m o d p ∏ d i ) x^{k-t}×\frac{x^t}{\prod d_i}=\frac{y}{\prod d_i}\pmod{\frac{p}{\prod d_i}} xkt×dixt=diy(moddip)
然后首先检验x=[0,t)是否为解,显然t是log级别的
如果[0,t)都不是解,由于x, x , p ∏ d i x,\frac{p}{\prod d_i} x,dip互质,BSGS求解即可
最后记得答案加上t,MOD一定要先除,map一定要用count查询元素
模板题[SPOJ3105]MOD

// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define int long long
#define enter putchar('\n')
#define space putchar(' ')
using namespace std;
template <class T> void read(T &x) {
    x = 0; bool f = 0; char ch = getchar();
    while (!(ch >= '0' && ch <= '9')) {if (ch == '-') f = 1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    if (f) x = -x;
}
template <class T> void write(T x) {
    if (x < 0) x = -x, putchar('-');
    if (x / 10) write(x / 10);
    putchar('0' + x % 10);
}
int n, x, MOD, y;
map<int, int> mp;
inline void Mul(int &x, int y) {x = x * y % MOD;}
inline int ksm(int a, int b) {int ret = 1; for (; b; b >>= 1, Mul(a, a)) if (b & 1) Mul(ret, a); return ret;}
inline int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
inline void exbsgs(int x, int y) {
    if (y == 1) {puts("0"); return;}
    int d, k = 1, t = 0;
    while ((d = gcd(x, MOD)) != 1) {
        if (y % d) {puts("No Solution"); return;}
        ++t, y /= d, MOD /= d; Mul(k, x / d); //MOD一定要先除
        if (k == y) {write(t); enter; return;}
    }
    int s = y, m = sqrt(MOD) + 1; mp.clear();
    for (int i = 0; i < m; i++) mp[s] = i, Mul(s, x);
    s = k, k = ksm(x, m);
    for (int i = 1; i <= m; i++) {
        Mul(s, k);
        if (mp.count(s)) {write(i * m - mp[s] + t); enter; return;} //一定要用count
    }
    puts("No Solution");
}
inline int C(int n, int m) {
    if (m > n) return 0;
    int a = 1, b = 1;
    for (int i = n - m + 1; i <= n; i++) Mul(a, i);
    for (int i = 1; i <= m; i++) Mul(b, i);
    return a * ksm(b, MOD - 2) % MOD;
}
inline int lucas(int n, int m) {
    if (m == 0) return 1;
    return (C(n % MOD, m % MOD) * lucas(n / MOD, m / MOD)) % MOD;
}
signed main() {
    #if 0
    read(n);
    while (n--) {
        int opt = 2;
        //read(opt);
        read(x), read(y), read(MOD);
        if (opt == 1) write(ksm(x, y)), enter;
        else if (opt == 2) exbsgs(x % MOD, y % MOD);
        else write(lucas(y, x)), enter;
    }
    #endif
    while (1) {
        read(x), read(MOD), read(y);
        if (!x && !y && !MOD) break;
        exbsgs(x % MOD, y % MOD);
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值