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

原题链接

简要题意:给定一个质数 \(p\),以及一个整数 \(a\),一个整数 \(n\),现在要求你计算一个最小的非负整数 \(x\),满足 \(a^x \equiv n \pmod p\).

本题是 BSGS (BaBy Step Giant Step),即大步小步算法。

下面我们将一步步引入该算法。考虑令 \(x = rt - s\),其中 \(s < t\),而 \(t\) 是我们给定的一个类似于 “块长” 的东西。

\[\begin{aligned} & a^{rt - s} \equiv n \pmod p \\ & a^{rt} \equiv n \times a^s \pmod p \\ & (a^t)^r \equiv n \times a^s \pmod p \\ \end{aligned} \]

注意到,这里我们可以用哈希进行处理。

\(n \times a^s\) 的值最多有 \(t\) 个,因为 \(s < t\).

\((a^t)^r\) 的值最多有 \(\lfloor \frac{p}{t} \rfloor\),因为 \(x \leq p\).

哈希自带一个 \(\text{log}\),加上快速幂,于是该程序时间复杂度为 \(\mathcal{O}(t \log^2 t + \frac{p}{t} \log^2 \frac{p}{t})\).

很显然,块长 \(t\) 在取到 \(\lfloor \sqrt{p} \rfloor\) 时时间复杂度最优。

时间复杂度:\(\mathcal{O}(\sqrt{p} \log^2 \sqrt{p})\). 这在 \(p = 10 ^ {12}\) 的时候仍然是足以通过的。

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

typedef long long ll;
ll p,a,n;
map<ll,ll> m;

inline ll pw(ll x,ll y) {
	ll ans=1; while(y) {
		if(y&1) ans=ans*x%p;
		x=x*x%p; y>>=1;
	} return ans;
}

int main() {
	scanf("%lld %lld %lld",&p,&a,&n);
	ll t = sqrt(p);
	for(ll s = 0 ; s < t ; s++) m[n * pw(a,s) % p] = s; // 计算式子右侧的值
	a = pw(a,t);
	ll ans = 1e17;
	for(ll r = 1 ; r <= t; r++) 
		if(m[pw(a,r)]) ans = min (ans , r * t - m[pw(a,r)]); // 寻找对应
	printf(ans == 1e17 ? "no solution" : "%d",ans);
	puts("");
	return 0;
}
posted @ 2021-12-23 22:56  bifanwen  阅读(45)  评论(1编辑  收藏  举报