【学习笔记】exBSGS

exBSGS

a x ≡ b ( m o d p ) a^x \equiv b \pmod p axb(modp)

跟 BSGS 差不多,只是多了 p p p 可以不为质数这一条件。

做法

首先你需要知道一个同余方程的性质:

给定一个同余式 a ≡ b ( m o d p ) a \equiv b\pmod p ab(modp)

若存在 d d d 满足 d ∣ a , d ∣ b , d ∣ p d|a,d|b,d|p da,db,dp,那么则有 a d ≡ b d ( m o d p d ) \frac{a}{d} \equiv \frac{b}{d}\pmod{\frac{p}{d}} dadb(moddp)

那么这题就非常简单了。

我们令 d = gcd ⁡ ( a , p ) d=\gcd(a,p) d=gcd(a,p),则可以将其转化为 a d × a x − 1 ≡ b d ( m o d p d ) \frac{a}{d} \times a^{x-1} \equiv \frac{b}{d} \pmod {\frac{p}{d}} da×ax1db(moddp),一直重复直到 a a a p p p 互质。

设执行了 c n t cnt cnt 次,那么则有 ( a d ) c n t × a x − c n t ≡ b d c n t ( m o d p d c n t ) (\frac{a}{d})^{cnt} \times a^{x-cnt} \equiv \frac{b}{d^{cnt}} \pmod {\frac{p}{d^{cnt}}} (da)cnt×axcntdcntb(moddcntp)。就可以将其转化为 BSGS 来做了。

Code

#include
#define IOS cin.tie(0),cout.tie(0),ios::sync_with_stdio(0)
#define mod 998244353
#define ll long long
#define db double
#define pb push_back
#define MS(x,y) memset(x,y,sizeof x)
using namespace std;
const int N=1e5+5,M=1e5+5;
const ll INF=1ll<<60;
void exgcd(ll a,ll b,ll &x,ll &y){
	if(!b) x=1,y=0;
	else exgcd(b,a%b,y,x),y-=a/b*x;
}
ll gcd(ll a,ll b){
	if(!b) return a;
	return gcd(b,a%b);
}
ll fpow(ll a,ll b,ll p){
	ll ans=1;
	for(;b;b>>=1){
		if(b&1) ans=ans*a%p;
		a=a*a%p; 
	}
	return ans;
}
ll calc(ll a,ll p){
	ll x=0,y=0;
	exgcd(a,p,x,y);
	x=(x%p+p)%p;
	return x;
}
ll BSGS(ll g,ll a,ll p){
	unordered_map<ll,ll> m;
	a%=p;
//	if(!g) return !a?1:-1;
	ll B=(ll)sqrt(p)+1;
	ll k=a,ng=calc(g,p),gB=1;
	for(int i=0;i<B;i++){
		if(!m[k]) m[k]=i+1;
		k=k*ng%p;
		gB=gB*g%p;
	}
	ll temp=1;
	for(int i=0;i<=B;i++){
		if(m[temp]) return (i*B%p+m[temp]-1)%p;
		temp=temp*gB%p;
	}
	return -1;
}
ll exBSGS(ll a,ll b,ll p){
	a%=p;b%=p;
	ll cnt=0,d=gcd(a,p),tot=1;
	while((d=gcd(a,p))^1){
		if(tot==b) return cnt;
		if(b%d) return -1;
		cnt++;b/=d;p/=d;
		tot=a/d*tot%p;
	}
	ll ntot=calc(tot,p);
	b=b*ntot%p;
	ll ans=BSGS(a,b,p);
	if(ans!=-1) return ans+cnt;
	return -1;
}
bool solve(){
	ll a,b,p;
	cin>>a>>p>>b;
	if(!p) return 0;
	ll ans=exBSGS(a,b,p);
	if(ans==-1) cout<<"No Solution\n";
	else cout<<ans<<"\n"; 
	return 1;
}
int main(){
	IOS;int T=1;
//	cin>>T;
	while(solve());
	return 0;
}

注:

  1. 如果 b b b 不被 d d d 整除,则直接返回无解。
  2. 答案可能小于 c n t cnt cnt,我们必须枚举 [ 0 , c n t − 1 ] [0,cnt−1] [0,cnt1] 的解,看是否存在解。

E N D \large{\mathbb{END}} END

你可能感兴趣的:(学习,笔记,算法)