【模板】扩展BSGS板子 POJ3243 Clever Y

鉴于CQOI2018居然考了一道BSGS的板子题,就默默得又复习了一下BSGS以及又学了EXBSGS,CQOI那道题太板了,朴素BSGS,可以直接参考我以前的文章:POJ2417高次同余方程

这个HASH表的模板是直接抄的,,不会啊,,看来下一步是有必要学一下HASH表了。

EXBSGS的不同于朴素BSGS的地方是,EXBSGS的模数可以不受到一定要是质数的影响。可以是任何数。

令 d = gcd(A, C) , A = ad, B = bd, C = cd
则 a
d ≡ bd (mod cd)
等价于 a ≡ b (mod c )

问题变成了求D * A^(x-cnt) ≡ B (mod C),因此我们先消除因子,不断地枚举r=gcd(a,c),然后b/=r,c/=r,base*=(a/r)(base是指的是大小步算法里面的大步块),然后将令x = i * m + j + cnt,cnt为消除的次数,方法就和朴素BSGS一样了。但是我们要考虑其x小于cnt的情况,于是,我们先要枚举cnt次,大约(log C)次,判断得到的是不是刚好等于B。

以下是code....

#include<map>
#include<cstdio>
#include<iostream>
#include<cmath>
typedef long long ll;
using namespace std;
ll gcd(ll a,ll b) { return !b?a:gcd(b,a%b); }

struct Hashmap
{
    static const int Ha=999917,maxe=46340;
    int E,lnk[Ha],son[maxe+5],nxt[maxe+5],w[maxe+5];
    int top,stk[maxe+5];
    void clear() {E=0;while (top) lnk[stk[top--]]=0;}
    void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];w[E]=INT_MAX;lnk[x]=E;}
    bool count(int y)
    {
        int x=y%Ha;
        for (int j=lnk[x];j;j=nxt[j])
            if (y==son[j]) return true;
        return false;
    }
    int& operator [] (int y)
    {
        int x=y%Ha;
        for (int j=lnk[x];j;j=nxt[j])
            if (y==son[j]) return w[j];
        Add(x,y);stk[++top]=x;return w[E];
    }
};
Hashmap ma;

ll exgcd(ll a,ll b,ll &x,ll &y)
{ 
	if(!b) { x=1; y=0; return a; }
	ll r=exgcd(b,a%b,x,y);
	ll tmp=x; x=y; y=tmp-(a/b)*y;
	return r;
}
ll EXbsgs(ll a,ll b,ll c)
{
	if(c==1) {if(!b) return a!=1; else return -1;}
	if(b==1) {if(a) return 0; else return -1;}
	if(a%c==0) {if(!b) return 1; else return -1;}
	ll num=0,r,d=1;
	while( (r=gcd(a,c))>1 )
	{
		if(b%r) return -1; ++num;
		b/=r; c/=r; d=d*a/r%c;
	}
	for(ll i=0,now=1;i<num;i++,now=now*a%c)
		if(now==b) return i;
	ll bb=1;
	ma.clear(); ll m=ceil(pow(c,0.5));
	for(ll i=0;i<m;i++)
	{
		if(!ma.count(bb)) ma[bb]=i; 
		bb=bb*a%c;
	}
	ll x,y; 
	for(ll i=0;i<m;i++)
	{
		r=exgcd(d,c,x,y);
		x=(x*b%c+c)%c;
		if(ma.count(x)) return i*m+ma[x]+num;
		d=d*bb%c;
	} 
	return -1;
}
int main()
{
	ll a,b,c,ans;
	while(233)
	{
		scanf("%lld%lld%lld",&a,&c,&b);
		if(a+b+c==0) return 0;
		ans=EXbsgs(a,b,c);
		ans==-1?printf("No Solution\n"):printf("%lld\n",ans);
	}
}

 

posted @ 2018-04-16 18:18  Newuser233  阅读(5)  评论(0)    收藏  举报