[SDOI2011][洛谷P2485]计算器(BSGS模板)

题面

https://www.luogu.com.cn/problem/P2485

题解

对于T=1,快速幂即可。
对于T=2,exgcd即可。
重点是T=3,需要使用BSGS算法。

BSGS算法

用来快速求解形如({a^x}{equiv}r(mod p))的指数同余方程的算法,适用范围是(gcd(a,p)=1)
由欧拉-费马定理可得(a^{phi(p)}{equiv}1(mod p))。下设(0<=x<{phi(p)})
设置“间隔”(T),那么x一定可以表示成(iT-j)(其中(1<=j<=T))的形式。下有

[a^{iT-j}{equiv}r{mod p} ]

[a^{iT}{equiv}r*a^j{mod p} ]

故只要某一个(a^{iT}(1<=i<={lceil{{phi(p)-1}over{T}} ceil}))以及某一个(r*a^j(1<=j<=T))相等,就得到了一个解(x=iT-j)

实现时只需要将所有的(r*a^j)预处理好放入Hash表内,在计算(a^{iT})的时候同步查询就可以了。

计算(r*a^j)的时间复杂度为(O(T)),计算(a^{iT})的时间复杂度是(O({{phi(p)}over{T}})),取(T=sqrt{phi(p)})即可保证总时间复杂度是(O(sqrt{phi(p)}))

回本题

给出(y),(z),(p),计算满足(y^x{equiv}z{mod{p}})的最小非负整数 (x)

保证(p)是质数。

首先考虑(p|y)的情况,即({gcd}(y,p){ ot=}1)的情况,此时不能适用BSGS算法

  • 1、(z=0)(x=1)即可
  • 2、(z=1)(x=0)即可
  • 3、others:无解

其他情况可以适用BSGS解决。

代码

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define rg register

inline ll read(){
	ll s = 0,ww = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
	return s * ww;
}

inline void write(ll x){
	if(x < 0)putchar('-'),x = -x;
	if(x > 9)write(x / 10);
	putchar('0' + x % 10);
}

ll mod,g;

inline ll check(ll x){
	return (x % mod + mod) % mod;
}

namespace ModCalc{
	inline void Inc(ll &x,ll y,ll mod){
		x += y;if(x >= mod)x -= mod;
	}
	
	inline void Dec(ll &x,ll y,ll mod){
		x -= y;if(x < 0)x += mod;
	}
	
	inline ll Add(ll x,ll y,ll mod){
		Inc(x,y,mod);return x;
	}
	
	inline ll Sub(ll x,ll y,ll mod){
		Dec(x,y,mod);return x;
	}
}
using namespace ModCalc;

inline ll power(ll a,ll n){
	ll x = a,s = 1;
	while(n){
		if(n & 1)s = s * x % mod;
		x = x * x % mod;
		n >>= 1;
	}
	return s;
}

inline ll exgcd(ll a,ll &x,ll b,ll &y){
	if(!b){
		x = 1,y = 0;
		return a;
	}
	ll g = exgcd(b,y,a%b,x);
	y -= a / b * x;
	return g; 
}

map<ll,ll>M;

int main(){
	ll T = read(),opt = read();
	if(opt == 1){
		while(T--){
			ll a = read(),n = read();
			mod = read();a %= mod;
			write(power(a,n));putchar('
');
		}
	}
	else if(opt == 2){
		while(T--){
			ll a = read(),r = read();
			mod = read();
			ll x,y;
			ll g = exgcd(a,x,mod,y);
			if(r % g != 0){
				puts("Orz, I cannot find x!");
				continue;
			}
			a /= g,r /= g,mod /= g;
			x = check(x * r);
			write(x);putchar('
');
		}
	}
	else{
		while(T--){
			ll a = read(),r = read();
			mod = read();a %= mod,r %= mod;
			if(!a){
				if(!r)puts("1");
				else if(r == 1)puts("0");
				else puts("Orz, I cannot find x!");
				continue;
			}
			ll T = (ll)round(sqrt(mod));
			ll a_T = power(a,T);
			M.clear();
			for(rg ll i = 1,cur = r * a % mod;i <= T;i++,cur = cur * a % mod)M[cur] = i;
			ll flag = 0;
			for(rg ll i = 1,cur = a_T;i * T - T <= mod - 2;i++,cur = cur * a_T % mod)if(M.count(cur)){
				write(Sub(i*T%(mod-1),M[cur],mod-1)),putchar('
');
				flag = 1;
				break;
			}
			if(!flag)puts("Orz, I cannot find x!");
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/xh092113/p/12255049.html