1. 程式人生 > 實用技巧 >拓展BSGS 學習筆記

拓展BSGS 學習筆記

承接上文

BSGS 演算法要求 \(a\)\(p\) 互質,但如果 \(a\)\(p\) 不互質怎麼辦呢?

這時候我們就引入了 \(EXBSGS\) 演算法。

還是求 \(a^x \equiv b \pmod p\) , 但 \(p\) 不一定是質數。

如果 \(a\)\(p\) 互質的話,那麼套用一下 \(BSGS\) 的模板就可以解決了。

現在我們的就需要把 \(p\) 變成和 \(a\) 互質。

\(g = gcd(a,p)\) ,則有:

\({a\over g} a^{x-1} \equiv {b\over g} (\bmod {p\over g} )\)

如果 \(b \%\)

\(g\neq 0\) 的話,此方程無解。

但如果 \(a\)\(p\over g\) 互質的話,我們可以用 \(BSGS\) 演算法求出一個解來。

反之繼續遞迴下去,直到 \(a\)\(p\) 互質即可。

同時在遞迴的時候,統計一下迭代的次數 \(k\),那麼最後方程的解即為 \(k + t\) ( \(t\)\(BSGS\) 求出來的解)。

要注意的一點是當 \({a \over g} = b\) 的時候,這時候我們不用繼續向下遞迴下去,此時 \(x = k\) 就是原方程的一組解。

模板題 P1495

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define int long long
int a,b,p;
int gcd(int a,int b)
{
	if(b == 0) return a;
	else return gcd(b,a%b);
}
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
int ksm(int a,int b)
{
	int res = 1;
	for(; b; b >>= 1)
	{
		if(b & 1) res = res * a % p;
		a = a * a % p;
	}
	return res;
}
void exgcd(int a,int b,int &x,int &y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return;
	}
	exgcd(b,a%b,y,x);
	y -= a / b * x;
}
int inv(int a,int p)//求a在模p下的逆元
{
	int x,y;
	exgcd(a,p,x,y);
	return (x % p + p) % p;
}
int BSGS(int k,int a,int b,int p)//ka^x = b (mod p)
{
	b = b * inv(k,p) % p;
	map<int,int> hash;
	int m = (int) sqrt(p) + 1;
	for(int i = 1; i <= m; i++)
	{
		b = b * a % p;//要一個一個的乘,否則會炸 long long
		hash[b] = i;
	}
	a = ksm(a,m), b = 1;
	for(int i = 1; i <= m; i++)
	{
		b = b * a % p;
		int j = hash.find(b) == hash.end() ? -1 : hash[b];
		if(j >= 0 && i * m - j >= 0) return i * m - j;
	}
	return -1;
}
int Exbsgs(int a,int b,int p)
{
	int k = 1, num = 0;
	while(gcd(a,p) != 1)//直到 a 和 p 互質可以用bsgs求出一組解來
	{
		int g = gcd(a,p);
		if(b % g != 0) return -1;//無解的情況
		k = k * (a/g) % p; num++;//統計迭代的次數
		if(k == b) return num;//係數 k = d的時候 k就是原方程的一個解
		p /= g; b /= g;
	}
	int tmp = BSGS(k,a,b,p);
	return tmp == -1 ? -1 : tmp + num;
}
signed main()
{
	while(1)
	{
		a = read(); p = read(); b = read();
		if(a == 0 && b == 0 && p == 0) break;
		int ans = Exbsgs(a,b,p);
		if(ans == -1) printf("No Solution\n");
		else printf("%lld\n",ans);
	}
	return 0;
}