BSGS/EXBSGS

BSGS

给定一个质数 p p p,以及一个整数 b b b,一个整数 n n n,现在要求你计算一个最小的非负整数 l l l,满足 b l ≡ n b^l\equiv n bln(mod p)

思路

因为 p p p为质数,所以可得 a φ ( p ) ≡ 1 a^{\varphi(p)}\equiv 1 aφ(p)1(mod p)
又因为 a 0 ≡ 1 a^0\equiv 1 a01(mod p);
so, 0 − φ ( p ) 0-\varphi(p) 0φ(p)是一个循环节,不难暴力~

开始:设 x = i m − k , 0 < = k < = m , m = s q r t ( p ) x=im-k,0<=k<=m,m=sqrt(p) x=imk,0<=k<=mm=sqrt(p)
方程变为 a i m − k ≡ b a^{im-k}\equiv b aimkb(mod p)
将两边同乘 a k a^k ak 可得 a i m ≡ a k b a^{im}\equiv a^kb aimakb(mod p)

于是我们可以分别遍历等式两边的取值,第一次相等时,即可求出最小值 i m − k im-k imk
Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll p,b,n,m;
map<int,int> vis;
ll ksm(ll a,ll b,ll p){
	ll res=1;
	while(b){
		if(b&1) res=res*a%p;
		b>>=1;a=a*a%p;
	}
	return res;
}
void work(){
	m=ceil(sqrt(p));
	for(ll i=0,t=n;i<=m;i++,t=t*b%p) vis[t]=i;
	for(ll i=1,tt=ksm(b,m,p),t=tt;i<=m;i++,t=t*tt%p){
		if(vis.count(t)){
			printf("%lld",i*m-vis[t]);
			exit(0);
		}
	}
	puts("no solution");
	return;
}
int main(){
	scanf("%lld%lld%lld",&p,&b,&n);
	work();
	return 0;
}

EXBSGS

其实就是不保证a与p互质(
开始搞!!
我们设 g = g c d ( a , p ) g=gcd(a,p) g=gcd(a,p)
原式变为 a x g ≡ b g \frac{a^x}{g}\equiv \frac{b}{g} gaxgb (mod p g \frac{p}{g} gp)
无解时,b%g!=0&&b!=1(b=1时令x=0)
于是乎 我们还可以得到 a x − 1 × a g ≡ b g a^{x-1}\times\frac{a}{g}\equiv\frac{b}{g} ax1×gagb(mod p g \frac{p}{g} gp)
p g \frac{p}{g} gp一定比p小,所以可以一直约到 a , p g a,\frac{p}{g} a,gp互质
n a = ∏ i k a g i na=\prod_i^k\frac{a}{g_i} na=ikgia
原式又可以转换为 a x − k ≡ b ∏ i k g × n a a^{x-k}\equiv\frac{b}{\prod_i^k g\times na} axkikg×nab(mod p ∏ i k g \frac{p}{\prod_i^k g} ikgp)
注意:b除以na时需要求逆元

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a,p,b,m;
int gcd(int a,int b){return !b ? a : gcd(b,a%b);}
void exgcd(int a,int b,int &x,int &y){
	if(!b) x=1,y=0;
	else exgcd(b,a%b,y,x),y-=a/b*x;
}
int inv(int a,int b){
	int x,y;
	exgcd(a,b,x,y);
	return (x%b+b)%b;
}
int ksm(int k,int s,int m){
	int res=1;
	while(s){
		if(s&1) res=res*k%m;
		s>>=1,k=k*k%m;
	}
	return res;
}
map<int,int> vis;
int bsgs(int a,int b,int p){
	vis.clear();
	m=ceil(sqrt(p));b%=p;
	for(int i=0,t=b;i<=m;i++,t=t*a%p) vis[t]=i;
	for(int i=1,tt=ksm(a,m,p),t=tt;i<=m;i++,t=tt*t%p){
		if(vis.count(t)){
			return (i*m-vis[t]+p)%p;
		}
	}
	return -1;
}
int exbsgs(int a,int b,int p){
	if(b==1||p==1) return 0;
	int g=gcd(a,p),k=0,na=1;
	while(g>1){
		if(b%g!=0) return -1;
		k++;b/=g;p/=g;na=na*(a/g)%p;
		if(na==b) return k;
		g=gcd(a,p);
	}
	int f=bsgs(a,b*inv(na,p)%p,p);
	if(f==-1) return -1;
	return f+k;
}
signed main(){
	while(scanf("%lld%lld%lld",&a,&p,&b)==3&&a&&p&&b){
		a%=p,b%=p;
		int ret=exbsgs(a,b,p);
		if(ret==-1) puts("No Solution");
		else printf("%lld\n",ret);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值