嘘~ 正在从服务器偷取页面 . . .


洛谷P3846 [TJOI2007] 可爱的质数/【模板】BSGS 题解

题目链接:P3846 [TJOI2007] 可爱的质数/【模板】BSGS

题意

给定一个质数 $p$,以及一个整数 $a$,一个整数 $b$,现在要求你计算一个最小的非负整数 $k$,满足 $a^k \equiv b \pmod p$。

输入格式

仅一行,有 $3$ 个整数,依次代表 $p, a, b$。

输出格式

仅一行,如果有 $k$ 满足该要求,输出最小的 $k$,否则输出 no solution

数据范围

保证 $2\le a,b < p<2^{31}$。

BSGS 是求模质数 $p$​ 意义下的解,ExBSGS 是求模任意数下的解。

这里求的解实际上并不是模意义下的 $\log$ ,因为离散对数函数定义在 $a$ 为原根的情况下

BSGS 全称 Baby Step,Giant Step,可以用于解决形如以下高次同余方程,其中 $a,b,p$ 给出

第一行就是本题,而第二行实际上是 N 次剩余的板子题,虽说也可以用 BSGS 但是比较复杂。

因为 $a,p$ 显然互质,所以可以在模 $p$ 意义下做关于 $a$ 的乘除运算。

记 $t = \lfloor\sqrt{p}\rfloor$ ,设 $k = i\cdot t - j(0 \le j < t)$ ,则

两侧同乘 $a^j$ 得

那么这有什么用呢?因为 $j$ 的取值仅有 $\mathcal{O}(\sqrt{p})$ ,所以同余式右侧的取值我们可以直接暴力算出来。

不妨把这些值存在一个哈希表内,然后枚举 $i \in [0,t]$ ,找左侧式子对应的值是否存在。

这样我们可以同时得到 $i,j$ ,又因为 $t$ 已知,所以 $k$ 就求出来了。

时间复杂度 $\mathcal{O}(\sqrt{p})$ ,听说能过 $p\le 10^{16}$ 。

代码:

// 2024年02月21日 17:33:40
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)())

int P;
int qpow(int a, int b)
{
    int r = 1;
    while(b)
    {
        if(b & 1) r = r * a % P;
        b >>= 1; a = a * a % P;
    }
    return r;
}
map<int,int> mp;
int BSGS(int a, int b)
{
    int t = sqrt(P) + 1;
    for(int i = 0; i < t; i++) mp[b * qpow(a, i) % P] = i;
    a = qpow(a, t);
    if(!a) return (b == 0 ? 1 : -1);
    for(int i = 1; i <= t; i++)
    {
        int val = qpow(a, i);
        int j = mp.find(val) == mp.end() ? -1 : mp[val];
        if(j >= 0 && i * t - j >= 0) return i * t - j;
    }
    return -1;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int a,b; cin >> P >> a >> b;
    int res = BSGS(a,b);
    if(res == -1) cout << "no solution\n";
    else cout << res << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录