[BZOJ2219]数论之神(BSGS)

题面

http://darkbzoj.tk/problem/2219

题解

前置知识

我们要求方程\(x^a = r({\mod M})\)(其中M是质数)在模M意义下的解x的数量。

首先将M的素因数分解式写出:\(M = {\prod_{i=1}^{k}}{p_i^{s_i}}\),其中\(p_1<p_2<…<p_k\)为奇素数,\(s_i{\in}Z^*\)

那么我们可以将原方程分解为多个方程:

\[\begin{cases} x^a {\equiv} r {\mod {p_1}^{s_1}} \\… \\x^a {\equiv} r {\mod {p_k}^{s_k}} \end{cases} \]

由中国剩余定理和乘法原理,这第一个方程在模\({p_1}^{s_1}\)意义下的解数\(A_1\)、……第k个方程在模\({p_k}^{s_k}\)意义下的解数\(A_k\)的乘积就是原方程的解数。

因此,现在只需要解决一个形如\(x^a{\equiv}r{\mod p^s}\)的方程在模\(p^s\)意义下的解数的问题。

不妨设\(r {\in} [0,p^s)\)。可以分成三种情况讨论:

  • 1、\(r=0\):这代表着只要\(p^{{\lceil}{\frac{s}{a}}{\rceil}} | x\)就满足方程了,解数为\(p^{s-{\lceil}{\frac{s}{a}}{\rceil}}\)

  • 2、\(r {\neq} 0\),设\(r=p^t*u\),其中\((u,p)=1\)

    • 2.1、\(t=0\):那么x没有约数p。

      \[x^a{\equiv}u{\mod p^s} \]

      设g为\(p^s\)的原根,再设\(m,n{\in}[0,\phi(p^s))\)使得\(x=g^m,u=g^n\)。(由于u,x均与p互质,所以满足条件的m,n一定存在)n可以通过BSGS算法求出,而我们想要求的答案转化为

      \[am{\equiv}n{\mod {\phi(p^s)}} \]

      在模\({\phi(p^s)}\)意义下的解数。那么取\(d=(a,{\phi(p^s)})\),若\(d{\nmid}n\)则无解,否则由裴蜀定理,恰有d组解。

    • 2.2、\(t{\neq}0\):那么此时x中含p的次数已经被确定。如果\(a{\nmid}t\)则无解;否则,确定了有\(v_p(x)={\frac{t}{a}}\)。那么设\(x=p^{\frac{t}{a}}*v ((v,p)=1)\),有

      \[v^a {\equiv} u {\mod p^{s-t}} \]

      此时,方程转为了2.1的形式,可以用2.1的方法,计算出此处v在模\(p^{s-t}\)意义下的解数N。

      由于\(x=p^{\frac{t}{a}}*v\),那么x在模\(p^s\)意义下的解数即为v在模\(p^{s-{\frac{t}{a}}}\)意义下的解数,也就是\(N*p^{t-{\frac{t}{a}}}\)

代码

#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 pn;
bool isp[32000+5];
ll pri[32000+5];

inline void Eular(){
	pn = 0;
	for(rg ll i = 2;i <= 32000;i++)isp[i] = 1;
	for(rg ll i = 2;i <= 32000;i++){
		if(isp[i])pri[++pn] = i;
		for(rg ll j = 1;i * pri[j] <= 32000;j++){
			isp[i * pri[j]] = 0;
			if(i % pri[j] == 0)break;
		}
	}
}

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

ll k;
ll p[30+5],s[30+5],P[30+5];

inline void divide(ll M,ll &k,ll *p,ll *s,ll *P){ //素因数分解 
	k = 0;
	ll T = (ll)round(sqrt(M));
	for(rg ll i = 1;i <= pn && pri[i] <= T;i++){
		if(M % pri[i] == 0){
			k++;
			p[k] = pri[i];
			for(P[k] = 1,s[k] = 0;M % p[k] == 0;M /= p[k])P[k] *= p[k],s[k]++;
		}
	}
	if(M != 1){
		k++;
		p[k] = P[k] = M;
		s[k] = 1;
	}
}

inline ll gcd(ll a,ll b){
	return b ? gcd(b,a % b) : a;
}

ll _k;
ll _p[30+5],_s[30+5],_P[30+5];

inline ll calcg(ll p,ll P){ //计算P的原根 
	ll phi = P / p * (p - 1);
	divide(phi,_k,_p,_s,_P);
	for(rg ll g = 2;;g++){
		bool b = 1;
		for(rg ll i = 1;i <= _k;i++)if(power(g,phi/_p[i],P) == 1){
			b = 0;
			break;
		}
		if(b)return g;
	}
}

unordered_map<ll,ll>Hash;

inline ll BSGS(ll g,ll u,ll phi,ll P){ //计算方程g^x=u(mod P)在模phi(P)意义下的解x 
	Hash.clear();
	ll T = (ll)ceil(sqrt(P));
	ll g_T = power(g,T,P);
	for(rg ll cur = u * g % P,i = 1;i <= T;i++,cur = cur * g % P)Hash[cur] = i;
	for(rg ll cur = g_T,i = 1;i <= T;i++,cur = cur * g_T % P)
	if(Hash.count(cur))return i * T - Hash[cur];	
}

inline ll solve(ll a,ll u,ll p,ll P){ //计算方程x^a=u(mod P)在模P意义下解x的个数 
	ll g = calcg(p,P);
	ll phi = P / p * (p - 1);
	ll n = BSGS(g,u,phi,P); 
	ll d = gcd(a,phi);
	if(n % d)return 0;
	else return d;
}

inline ll calc(ll a,ll r,ll p,ll s,ll P){ //计算各A[i]。P=p^s 
	r %= P;
	if(!r)return power(p,s - (ll)ceil(1.0*s/a),0);
	ll t = 0,u;
	while(r % p == 0)r /= p,P /= p,t++; 
	u = r;
	if(!t)return solve(a,u,p,P);
	else{
		if(t % a)return 0;
		else return power(p,t - t / a,0) * solve(a,u,p,P); //此处的P已经变为p^(s-t)	
	}
}

int main(){
	Eular();
	ll T = read();
	while(T--){
		ll a = read(),r = read(),M = read() * 2 + 1;
		divide(M,k,p,s,P);
		ll ans = 1;
		for(rg ll i = 1;i <= k;i++)ans *= calc(a,r,p[i],s[i],P[i]);	
		write(ans),putchar('\n');
	}
	return 0;
}

posted @ 2020-02-05 18:25  coder66  阅读(206)  评论(0编辑  收藏  举报