【数学】扩展 BSGS

前置芝士:\(\rm BSGS\)

\(a,b,p\) 均为整数时,请求出方程

\[a^x\equiv b\pmod p \]

的最小非负整数解.

对于普通的 \(\rm BSGS\),必须在 \(a,p\) 互质时才能求.

\(a,p\) 不互质时,需要用到扩展 \(\rm BSGS\),即 \(\rm exBSGS\).

我们考虑:

\[a^x\equiv b\pmod p\\ 设 \gcd(a,p)=g_1\\ \dfrac{a^x}{g_1}\equiv \dfrac{b}{g_1}\pmod{\dfrac{p}{g_1}} \]

那么当 \(g_1\nmid b\) 时,无解.

否则继续:

\[a^{x-1}\cdot\dfrac{a}{g_1}\equiv \dfrac{b}{g_1}\pmod{\dfrac{p}{g_1}}\\ 设 \gcd(a,\dfrac{p}{g_1})=g_2\\ a^{x-2}\cdot\dfrac{a^2}{g_1g_2}\equiv\dfrac{b}{g_1g_2}\pmod{\dfrac{p}{g_1g_2}} \]

一直往下除,直到 \(a,\dfrac{p}{g_1g_2\dots g_k}\) 互质,其中 \(k\) 是除的次数.

我们设 \(g_1g_2\cdots g_k=f\),那么最终就是

\[a^{x-k}\cdot\dfrac{a^k}{f}\equiv\dfrac{b}{f}\pmod{\dfrac{p}{f}} \]

这时 \(a,\dfrac{p}{f}\) 互质,所以 \(a^k,\dfrac{p}{f}\) 互质,则 \(\dfrac{a^k}{f},\dfrac{p}{f}\) 互质,那么 \(\dfrac{a^k}{f}\) 在模 \(\dfrac{p}{f}\) 的意义下有逆元,所以

\[a^{x-k}\equiv\dfrac{b}{f}\cdot\operatorname{inv}(\dfrac{a^k}{f})\pmod{\dfrac{p}{f}} \]

这样就转化成了一个普通的 \(\rm BSGS\).

预处理的时间复杂度为 \(O(p\log p)\)

P4195 【模板】扩展 BSGS/exBSGS

\(\text{Code}\)

#include <iostream>
#include <cstdio>
#include <map>
#include <cmath>
typedef long long ll;
using namespace std;

int phi(int p)
{
	int ans = p;
	for (int i = 2; (ll)i * i <= (ll)p; i++)
	{
		if (p % i == 0)
		{
			ans = ans / i * (i - 1);
			while (p % i == 0)
			{
				p /= i;
			}
		}
	}
	if (p != 1)
	{
		ans = ans / p * (p - 1);
	}
	return ans;
}

int bsgs(int a, int b, int p)
{
	map<int, int> hash;
	int t = ceil(sqrt(phi(p))), aj = 1;
	for (int j = 0; j < t; j++)
	{
		int val = (ll)b * aj % p;
		hash[val] = j;
		aj = (ll)aj * a % p;
	}
	a = aj;
	if (!a)
	{
		if (!b)
		{
			return 1;
		}
		return -1;
	}
	int ai = 1;
	for (int i = 0; i <= t; i++)
	{
		if (hash.find(ai) != hash.end())
		{
			int j = hash[ai];
			if (i * t - j >= 0)
			{
				return i * t - j;
			}
		}
		ai = (ll)ai * a % p;
	}
	return -1;
}

int gcd(int a, int b)
{
	if (!b)
	{
		return a;
	}
	return gcd(b, a % b);
}

int x, y;

void exgcd(int a, int b)
{
	if (!b)
	{
		x = 1, y = 0;
		return;
	}
	exgcd(b, a % b);
	int tmp = x;
	x = y;
	y = tmp - a / b * y;
}

int inv(int a, int p)
{
	exgcd(a, p);
	x = (x % p + p) % p;
	return x;
}

int exbsgs(int a, int b, int p)
{
	if (b == 1 || p == 1) //特判
	{
		return 0;
	}
	a %= p, b %= p;
	int g = gcd(a, p), f = 1, k = 0;
	while (g > 1)
	{
		if (b % g)
		{
			return -1;
		}
		k++;
		b /= g, p /= g;
		f = (ll)f * (a / g) % p; //一定要先把 p 除以 g 再取模
		if (f == b) //相等就可以直接返回
		{
			return k;
		}
		g = gcd(a, p);
	}
	int res = bsgs(a, (ll)b * inv(f, p) % p, p);
	if (res == -1)
	{
		return -1;
	}
	return res + k;
}

int main()
{
	int a, b, p;
	while (scanf("%d%d%d", &a, &p, &b), a || b || p)
	{
		int res = exbsgs(a, b, p);
		if (res == -1)
		{
			puts("No Solution");
		}
		else
		{
			printf("%d\n", res);
		}
	}
	return 0;
}
posted @ 2021-11-07 09:32  mango09  阅读(37)  评论(0编辑  收藏  举报
-->