poj 3243 Clever Y && 1467: Pku3243 clever Y【扩展BSGS】

扩展BSGS的板子
对于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} \)
如此循环到ap互质,然后正常BSGS求即可
最后答案加上循环次数,即当前的x是经过几次减一得到的
注意有很多关于0和1的特判
以及这道题在bzoj上是可以用map的,但是poj上只能用hash
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版,大概比map快三到四倍

#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;
}
posted @ 2018-01-26 16:28  lokiii  阅读(225)  评论(0编辑  收藏  举报