跳到主要内容
原文316 词数2 分钟

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

概述

给质数 p 与整数 b、n,求最小非负整数 l 使 b 的 l 次方模 p 等于 n,无解则报告。gcd(b,p) 为 1 时用大步小步算法:设 m 为 sqrt p 上取整,把 l 写成 im 减 j,小步枚举 j 将 n 乘 b 的 j 次方连同 j 存入哈希表,大步枚举 i 算 b 的 im 次方查表命中即得 l。i 从小到大且哈希表对相同键保留较大的 j,首个命中即最小解,l 等于 0 单独特判。时间复杂度为 O(sqrt p)。

参考资料​

题意简述​

给定质数 pp 与整数 b,nb,n,求最小的非负整数 ll,使 bl≡n(modp)b^l\equiv n\pmod p,无解则报告。

解题思路​

设 m=⌈p⌉m=\lceil\sqrt p\rceil。pp 为质数,b≢0b\not\equiv 0 时 gcd⁡(b,p)=1\gcd(b,p)=1,可用 BSGS(Baby-Step Giant-Step,大步小步)。

把 ll 写作 l=im−jl=im-j(0≤j<m0\le j<m),代入 bl≡nb^l\equiv n 得:

bim≡n⋅bj(modp)b^{im}\equiv n\cdot b^{j}\pmod p

两侧分别枚举:

  1. 小步:枚举 jj 从 00 到 m−1m-1,将 n⋅bjn\cdot b^{j} 连同 jj 存入哈希表;
  2. 大步:枚举 ii 从 11 到 mm,算出 bimb^{im} 查表,命中即得 l=im−jl=im-j。

若有解,最小解必小于 p≤m2p\le m^2,故枚举范围足以覆盖。ii 自小到大、哈希表对相同键保留较大的 jj,首个命中即最小的 ll。l=0l=0(即 n≡1n\equiv 1)单独特判。

时间复杂度为 O(p)O(\sqrt p)。

参考代码​

521 Bcpp
#include <bits/stdc++.h>
using namespace std;

using ll=long long;
ll bsgs(ll b,ll n,ll p)
{
if(n==1)return 0;
unordered_map<ll,ll> mp;
ll m=sqrt(p),k=n;
for(ll j=0;j<m;j++)
{
mp[k]=j;
k=k*b%p;
}
ll t=1;
for(ll i=0;i<m;i++)t=t*b%p;
k=1;
for(ll i=1;i<=m;i++)
{
k=k*t%p;
if(mp.count(k))return i*m-mp[k];
}
return -1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll p,b,n;
cin>>p>>b>>n;
ll res=bsgs(b,n,p);
if(res==-1)cout<<"no solution"<<'\n';
else cout<<res<<'\n';
return 0;
}