版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
BSGS(baby-step gaint-step),大步小步算法,该算法可以在时间复杂度内求解
算法描述
我们令,,这样我们可以保证
由于我们知道,我们可以先枚举B算出右边 ,存在一个hash表里面,然后再枚举A计算左边的的值,然后去判断hash表里面是否有这个值,如果有,我们就得到了 。
原根
, 为 的一个原根。
所有原根
若为的一个原根,则集合包含所有原根,由此如果有原根,则一共有个原根关于模两两互不同余
一个原根
,为的不同素因子,当且仅当 对于任意的 成立,为的一个原根
了解了原根以后,我们就可以在仅当是素数时,就可以求解方程
,由于是一个素数,则一定存在一个原根,因此对于模下的任意,存在唯一一个满足 。
于是我们令,所以,于是这就转换成了一个BSGS模型,可以算出,
求出一个解以后,如何得到所有解
既然,,那么 ,我们令
于是,
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) // 求最大公约数
{
if(b == 0) return a;
while(b) {
ll t = a;
a = b;
b = t % b;
}
return a;
}
ll power(ll a, ll b, ll p) // 快速幂
{
ll ans = 1;
while(b) {
if(b & 1) ans = (ans * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ans;
}
ll generator(ll p) // 求模p的原根
{
vector<ll> fact;
ll phi = p - 1, n = phi; // phi(p) = p - 1, p 为素数
for(ll i = 2; i * i <= n; i++) { // 素因子分解
if(n % i == 0) {
fact.push_back(i);
while(n % i == 0) n /= i;
}
}
if(n > 1) fact.push_back(n);
for(ll res = 2; res <= p; res++) { // 枚举每一可能的值
bool ok = true;
for(vector<ll>::iterator it = fact.begin(); it != fact.end(); it++) {
if(power(res, phi / (*it), p) == 1) { // 对于每一个素因子p_i, a^{phi(p)/p_i} != 1 mod p 才为原根
ok = false;
break;
}
}
if(ok) return res;
}
return -1;
}
void BSGS(ll k, ll a, ll n) // x^k = a mod n
{
if(a == 0) {
printf("1\n0\n");
return ;
}
ll g = generator(n); // 原根
ll sq = (ll)sqrt(n + .0) + 1; // sqrt(n) 向上取整
vector<pair<ll, int> > dec(sq);
// 枚举 A
for(ll i = 1; i <= sq; i++) dec[i-1] = make_pair(power(g, i * sq * k % (n - 1), n), i);
sort(dec.begin(), dec.end());
ll res = -1;
// 枚举 B
for(int i = 1; i <= sq; i++) {
ll my = power(g, i * k % (n - 1), n) * a % n;
vector<pair<ll, int> >::iterator it = lower_bound(dec.begin(), dec.end(), make_pair(my, 0));
if(it != dec.end() && it->first == my) {
res = it->second * sq - i; // A sqrt(n) - B
break;
}
}
if(res == -1) {
printf("0\n");
return ;
}
// 得到所有的答案
ll delta = (n - 1) / gcd(n - 1, k);
vector<ll> ans;
for(ll cur = res % delta; cur < n-1; cur += delta) ans.push_back(power(g, cur, n));
sort(ans.begin(), ans.end());
printf("%d\n", ans.size());
for(vector<ll>::iterator it = ans.begin(); it != ans.end(); it++) cout << *it << endl;
return ;
}
int main()
{
ll p, k, a;
while(scanf("%lld %lld %lld", &p, &k, &a) == 3) {
BSGS(k, a, p);
}
return 0;
}