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

BSGS本质上是一个分块算法。

我们考虑暴力求解的过程,显然答案的周期为$p$,所以我们只需要求得p之内的答案即可。

此时依然可能有多个解。

这个时候,我们只需要枚举1到p利用快速幂求值即可。

不过这太慢了,我们考虑使用分块的方法

我们把p分为$m=\sqrt p$块

我们求出每一块的端点值即$a^0,a^m,a^{2m},a^{3m}...a^{(m-1)m}$

对于每一个块的内部,我们预处理出所有可能的值,即$a^0,a^1...a^m$

枚举每一个端点值,查找端点值内部有没有某一个点能够满足原题条件。

形式化的请看oi-wiki

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define int long long
using namespace std;
inline int r()
{
	int s=0,k=1;char c=getchar();
	while(!isdigit(c))
	{
		if(c=='-')k=-1;
		c=getchar();
	}
	while(isdigit(c))
	{
		s=s*10+c-'0';
		c=getchar();
	}
	return s*k;
}
int p,b,n;
int gcd(int a,int b)
{
	if(!b)return a;
	return gcd(b,a%b);
}
map<int,int>m;
int pw(int a,int b,int mod)
{
	int base=a,ans=1;
	while(b)
	{
		if(b&1)
		{
			ans*=base;
			ans%=mod;
		}
		base*=base;
		base%=mod;
		b>>=1;
	}
	return ans;
}
signed main()
{
	p=r();b=r();n=r();
	int g=gcd(b,p);
	if(n%g)
	{
		cout<<"no solution"<<endl;
		return 0;
	}
	n/=g;p/=g;b/=g;
	int s=sqrt(p)+1;
	int now=1;
	for(int i=1;i<=s;i++)//b^i
	{
		now*=b;
		now%=p;
		if(m.find(now)==m.end())m[now]=i;
	}
	for(int i=0;i<=s;i++)//根号分块 si+j
	{
		int tmp=pw(b,i*s,p);
		tmp=pw(tmp,p-2,p);
		int x=n*tmp;
		x%=p;
		if(m.find(x)!=m.end())
		{
			cout<<i*s+m[x];
			return 0;
		}
	}
	cout<<"no solution"; 
}
posted @ 2021-07-17 11:16  lei_yu  阅读(45)  评论(0编辑  收藏  举报