BSGS

用途:求\( a^x \equiv b (mod\ p) 中的x \)

一、对于p为质数的情况

此时 \( 0 \leq x \leq p-1 \)

设 \( m=\left \lceil \sqrt{p} \right \rceil ,x=i*m-j \)这里-的作用是避免逆元

于是可以把式子变形成这样: \( a^{im}\equiv ba^j(mod\ p) \)

枚举右边 \( 0 \leq j <m \),用map或者hash以模数为下标来存每一个j

枚举左边\( 0 \leq i <m \) ,在map或者hash中查找对应的模数

二、对于gcd(a,p)==1的情况

此时 \( 0 \leq x \leq \varphi(p) \)

其余同上

三、对于gcd(a,p)>1的情况

即扩展BSGS

把式子变成等式的形式:\( a^x+yp=b \)

设\( g=gcd(a,p) \)

那么两边同时除以g就会变成:\( \frac{a}{g} a^{x-1}+y\frac{p}{g}=\frac{b}{g} \)

如此循环到情况二,然后正常求即可

最后答案加上循环次数,即当前的x是经过几次减一得到的

注意有很多关于0和1的特判

扩展BSGS模板:

//map
#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
using namespace std;
int a,b,p,ans;
map<int,int>mp;
int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
}
int ksm(int a,int b,int p)
{
	int r=1;
	while(b)
	{
		if(b&1)
			r=(long long)r*a%p;
		a=(long long)a*a%p;
		b>>=1;
	}
	return r;
}
int BSGS(int a,int b,int p)
{
	a%=p,b%=p;
	if(b==1)
		return 0;
	int cnt=0,d=1;
	for(int g=gcd(a,p);g!=1;g=gcd(a,p))
	{
		if(b%g)
			return -1;
		p/=g,b/=g;
		d=(long long)d*a/g%p;
		cnt++;
		if(b==d)
			return cnt;
	}
	mp.clear();
	int m=ceil(sqrt(p)),t=b;
	for(int i=0;i<m;i++)
	{
		mp[t]=i;
		t=(long long)t*a%p;
	}
	int g=ksm(a,m,p);
	t=(long long)d*g%p;
	for(int i=1;i<=m+1;i++)
	{
		if(mp[t])
			return cnt+i*m-mp[t];
		t=(long long)t*g%p;
	}
	return -1;
} 
int main()
{
	while(scanf("%d%d%d",&a,&p,&b)&&a+b+p)
	{
		if(p==1)
		{
			puts("0");
			continue;
		}
		ans=BSGS(a,b,p);
		if(ans==-1)
			puts("No Solution");
        else 
			printf("%d\n",ans);
	}
	return 0;
}
//hash
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int mod=739391,N=2e6;
int a,b,p,ans,ti,v[N],con;
struct qwe
{
	int b,v,ne;
}ha[N];
void ins(int w,int b,int va)
{//cout<<va<<endl;
	if(v[w]!=ti)
	{
		v[w]=ti;
		ha[w].v=va;
		ha[w].b=b;
		ha[w].ne=-1;
		return;
	}
	for(;ha[w].ne!=-1;w=ha[w].ne)
		if(ha[w].b==b)
			return;
	ha[w].ne=++con;
	ha[con].ne=-1;
	ha[con].v=va;
	ha[con].b=b;
}
int find(int w,int b)
{
	if(v[w]!=ti)
		return 0;
	for(;w!=-1;w=ha[w].ne)
		if(ha[w].b==b)
			return ha[w].v;
	return 0;
}
int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
}
int ksm(int a,int b,int p)
{
	int r=1;
	while(b)
	{
		if(b&1)
			r=(long long)r*a%p;
		a=(long long)a*a%p;
		b>>=1;
	}
	return r;
}
int BSGS(int a,int b,int p)
{
	a%=p,b%=p;
	if(b==1)
		return 0;
	int cnt=0,d=1;
	for(int g=gcd(a,p);g!=1;g=gcd(a,p))
	{
		if(b%g)
			return -1;
		p/=g,b/=g;
		d=(long long)d*a/g%p;
		cnt++;
		if(b==d)
			return cnt;
	}
	con=mod,ti++;
	int m=ceil(sqrt(p)),t=b;
	for(int i=0;i<m;i++)
	{
		ins(t%mod,t,i);
		t=(long long)t*a%p;
	}
	int g=ksm(a,m,p),now;
	t=(long long)d*g%p;
	for(int i=1;i<=m+1;i++)
	{
		if(now=find(t%mod,t))
			return cnt+i*m-now;
		t=(long long)t*g%p;
	}
	return -1;
} 
int main()
{
	while(scanf("%d%d%d",&a,&p,&b)&&a+b+p)
	{
		if(p==1)
		{
			puts("0");
			continue;
		}
		ans=BSGS(a,b,p);
		if(ans==-1)
			puts("No Solution");
        else 
			printf("%d\n",ans);
	}
	return 0;
}

模板题:

普通BSGS bzoj 3239 && 2480 http://www.cnblogs.com/lokiii/p/8359935.html
扩展BSGS poj 3243 && 1467 http://www.cnblogs.com/lokiii/p/8360202.html
其他题:

bzoj 2242 http://www.cnblogs.com/lokiii/p/8360272.html
bzoj 3122 http://www.cnblogs.com/lokiii/p/8360164.html

posted @ 2018-01-26 17:01  lokiii  阅读(255)  评论(0编辑  收藏  举报