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

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


洛谷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\) 给出 \[ a^x\equiv b \pmod{p}\\ x^a \equiv b \pmod{p} \] 第一行就是本题,而第二行实际上是 N 次剩余的板子题,虽说也可以用 BSGS 但是比较复杂。

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

\(t = \lfloor\sqrt{p}\rfloor\) ,设 \(k = i\cdot t - j(0 \le j < t)\) ,则 \[ a^{i\cdot t - j} \equiv b \pmod{p} \] 两侧同乘 \(a^j\)\[ (a^{t})^i \equiv b \cdot a^j\pmod{p} \] 那么这有什么用呢?因为 \(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 !
评论
  目录