BSGS

BSGS

本质是根号分治

  • 用途:求解\(A^x\equiv B\pmod p\)(a,p互质)
  • 做法:将\(x\)变为\(im-j\),则原式变为\(A^{im}\equiv BA^j \pmod p\)。枚举j,将每一个\(BA^j\)插入hash中,然后再枚举i,查询\(a^{im}\)是否出现,若出现,返回\(im-j\)。注意特判,当\(A\bmod p =0 \& B\bmod p = 0\)时,为1,当\(A\bmod p =0 \& B\bmod p \ne 0\)时,无解。
点击查看代码
inline int BSGS(int y,int z,int mod){
	if(y == 0 && z == 0) return 1;
	if(y == 0 && z != 0) return -1;
	unordered_map<int,int> mp;
	int t = sqrt(mod)+1,now = z%mod;
	for(int i = 0;i <= t; ++i){
		mp[now] = i;
		now = 1ll * now * y % mod;
	}
	int Ym = power(y,t,mod);now = 1;
	for(int i = 1;i <= t; ++i){
		now = 1ll * Ym * now % mod;
		if(mp.count(now)){
			return i*t-mp[now];
		}
	}
	return -1;
}

例题:计算器

第一问快速幂,第二问逆元,注意特判y%p=0时无解,第三问bsgs板子

点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int power(int a,int b,int mod){
	int res = 1;
	while(b){
		if(b&1) res = 1ll * res * a % mod;
		a = 1ll * a * a % mod;
		b >>= 1;
	}
	return res;
}
inline int BSGS(int y,int z,int mod){
	if(y == 0 && z == 0) return 1;
	if(y == 0 && z != 0) return -1;
	unordered_map<int,int> mp;
	int t = sqrt(mod)+1,now = z%mod;
	for(int i = 0;i <= t; ++i){
		mp[now] = i;
		now = 1ll * now * y % mod;
	}
	int Ym = power(y,t,mod);now = 1;
	for(int i = 1;i <= t; ++i){
		now = 1ll * Ym * now % mod;
		if(mp.count(now)){
			return i*t-mp[now];
		}
	}
	return -1;
}
signed main(){
	cin.tie(0)->sync_with_stdio(false);
	cout.tie(0)->sync_with_stdio(false);
	int T,k;
	cin>>T>>k;
	while(T--){
		int y,z,mod;
		cin>>y>>z>>mod;
		if(k == 1)cout<<power(y,z,mod)<<'\n';
		if(k == 2){
			if(y%mod == 0) cout<<"Orz, I cannot find x!\n";
			else cout<<1ll*z*power(y,mod-2,mod)%mod<<'\n';
		} 
		if(k == 3){
			y %= mod;z%=mod;
			int ans = BSGS(y,z,mod);
			if(ans == -1) cout<<"Orz, I cannot find x!\n";
			else cout<<ans<<'\n';
		}
	} 
} 

ExBSGS

  • 用途:求解\(a^x\equiv b\pmod p\quad (a,b,p\in \mathbb{Z^+})\)
    做法:想办法让其变得可以用BSGS求解,那么就是使\(\gcd(a,p) = 1\)。令\(d_1=\gcd(a,p)\),若\(d_1\nmid b\)无解,反之同时除以\(d_1\),得到

\[\frac{a}{d_1}\times a^{x-1}\equiv \frac{b}{d_1}\pmod{\frac{m}{d_1}} \]

若仍然不互质,重复以上操作,直至\(a\perp \frac{m}{d_1d_2d_3\dotsb d_k}\)

\(D = \prod_{i-1}^kd_i\),原方程变成了酱紫

\[\frac{a^k}{D}a^{x-1}\equiv \frac{b}{D}\pmod{\frac{m}{D}} \]

因为\(a\perp \frac{m}{D}\),所以\(\frac{a^k}{D}\perp\frac{m}{D}\),求逆元,扔到等式右边,用bsgs求出\(x-k\)加上k

当解小于k时,提前枚举就好了。

注意\(\frac{m}{D}\)不一定为素数,但\(\gcd(\frac{a^k}{D},\frac{m}{D})=1\),所以逆元要用exgcd求

点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
using ll=long long;using ull=unsigned long long;
#ifdef LOCAL
    FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
    // FILE *ErrFile=errfile("err.err");
#else
    FILE *Infile = stdin,*OutFile = stdout;
    //FILE *ErrFile = stderr;
#endif
inline int power(int a,int b,int mod){
    int res = 1;
    while(b){
        if(b&1) res = 1ll * res * a % mod;
        b >>= 1;
        a = 1ll * a * a % mod;
    }
    return res;
}
int exgcd(int a,int b,int &x,int &y){
    if(!b)return x=1,y=0,a;
    int res = exgcd(b,a%b,y,x);
    y -= a/b*x;
    return res;
}
inline int BSGS(int a,int b,int mod){
    a %= mod,b %= mod;
    if(!a) return (b?-1:1);
    __gnu_pbds::gp_hash_table<int,int> mp;
    int t = sqrt(mod)+1,res = b;
    for(int i = 0;i <= t; ++i){
        mp[res] = i;
        res = 1ll * a * res % mod;
    }
    a = power(a,t,mod),res = a;
    for(int i = 1;i <= t; ++i){
        if(mp[res]){
            return i*t-mp[res];
        }
        res = 1ll * res * a % mod;
    }
    return -1;
}
inline int ExBSGS(int a,int b,int mod){
    a %= mod,b %= mod;
    if(b == 1 || mod == 1) return 0;
    if(!a) return (b?-1:1);
    int tot = 0,gcd = 0,now = 1;
    while((gcd = __gcd(a,mod))^1){
        if(b%gcd) return -1;
        mod /= gcd;b /= gcd;tot++;
        now = 1ll * now * (a/gcd) % mod;
        if(now == b) return tot;
    }
    int x,y;
    exgcd(now,mod,x,y);
    x = (x%mod + mod) % mod;
    int ans = BSGS(a,1ll * b * x % mod,mod);
    if(ans == -1) return -1;
    else return ans + tot;
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cout.tie(nullptr)->sync_with_stdio(false);
    int a,p,b;
    while(cin>>a>>p>>b&&a&&b&&p){
        int ans = ExBSGS(a,b,p);
        if(ans == -1) cout<<"No Solution\n";
        else cout<<ans<<'\n';
    }
}

posted @ 2024-07-23 07:27  CuFeO4  阅读(8)  评论(0编辑  收藏  举报