BZOJ2219 数论之神 数论 中国剩余定理 原根 BSGS

原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2219.html

题目传送门 - BZOJ2219

题意

  求同余方程 $x^A\equiv B \pmod{C}$ 的解的个数,其中 $C$ 为一个奇数。

  $1\leq A,B\leq 10^9,1\leq \lfloor C/2 \rfloor \leq 5\times 10^8$

题解

 

 

 

UPD(2018-09-10): 

  详见数论总结。 

  传送门 - https://www.cnblogs.com/zhouzhendong/p/Number-theory-Residue-System.html

 

 

代码

 

#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int read(){
	int x=0;
	char ch=getchar();
	while (!isdigit(ch))
		ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
int pcnt,f[N],Prime[N];
void Get_Prime(int n){
	memset(f,0,sizeof f);
	pcnt=0;
	for (int i=2;i<=n;i++){
		if (f[i])
			continue;
		Prime[++pcnt]=i;
		for (int j=i+i;j<=n;j+=i)
			f[j]=1;
	}
}
void Divide(int x,int *p,int *q,int &cnt){
	cnt=0;
	for (int i=1;i<=pcnt&&Prime[i]*Prime[i]<=x;i++){
		if (x%Prime[i])
			continue;
		p[++cnt]=Prime[i],q[cnt]=0;
		while (x%p[cnt]==0)
			x/=p[cnt],q[cnt]++;
	}
	if (x>1)
		p[++cnt]=x,q[cnt]=1;
}
int Pow(int x,int y,int mod){
	int ans=1;
	for (;y;y>>=1,x=1LL*x*x%mod)
		if (y&1)
			ans=1LL*ans*x%mod;
	return ans;
}
int Pow(int x,int y){
	return Pow(x,y,2e9);
}
int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
int Fac[50],Fac_cnt=0;
bool Get_g_Check(int P,int C,int x){
	int phi=Pow(P,C-1)*(P-1),pw=Pow(P,C);
	if (C>1&&Pow(x,phi/P,pw)==1)
		return 0;
	for (int i=1;i<=Fac_cnt;i++)
		if (Pow(x,phi/Fac[i],pw)==1)
			return 0;
	return 1;
}
int Get_g(int P,int C){
	int v=P-1;
	Fac_cnt=0;
	for (int i=1;i<=pcnt&&Prime[i]*Prime[i]<=v;i++)
		if (v%Prime[i]==0){
			Fac[++Fac_cnt]=Prime[i];
			while (v%Prime[i]==0)
				v/=Prime[i];
		}
	if (v>1)
		Fac[++Fac_cnt]=v;
	for (int i=2;;i++)
		if (Get_g_Check(P,C,i))
			return i;
	return -1;
}
struct hash_map{
	static const int Ti=233,mod=1<<16;
	int cnt,k[mod+1],v[mod+1],nxt[mod+1],fst[mod+1];
	int Hash(int x){
		int v=x&(mod-1);
		return v==0?mod:v; 
	}
	void clear(){
		cnt=0;
		memset(fst,0,sizeof fst);
	}
	void update(int x,int a){
		int y=Hash(x);
		for (int p=fst[y];p;p=nxt[p])
			if (k[p]==x){
				v[p]=a;
				return;
			}
		k[++cnt]=x,nxt[cnt]=fst[y],fst[y]=cnt,v[cnt]=a;
		return;
	}
	int find(int x){
		int y=Hash(x);
		for (int p=fst[y];p;p=nxt[p])
			if (k[p]==x)
				return v[p];
		return 0;
	}
	int &operator [] (int x){
		int y=Hash(x);
		for (int p=fst[y];p;p=nxt[p])
			if (k[p]==x)
				return v[p];
		k[++cnt]=x,nxt[cnt]=fst[y],fst[y]=cnt;
		return v[cnt]=0;
	}
}Map;
int BSGS(int A,int B,int P){
	int M=max((int)(0.8*sqrt(1.0*P)),1),AM=Pow(A,M,P);
	Map.clear();
	for (int b=0,pw=B;b<M;b++,pw=1LL*pw*A%P)
		Map.update(pw,b+1);
	for (int a=M,pw=AM;a-M<P;a+=M,pw=1LL*pw*AM%P){
		int v=Map.find(pw);
		if (v)
			return a-(v-1);
	}
	return -1;
}
int RHD(int A,int B,int P,int C){
	int g=Get_g(P,C);
	int t=BSGS(g,B,Pow(P,C));
	int mod=(P-1)*Pow(P,C-1);
	int GCD=gcd(mod,gcd(A,t));
	return gcd(A,mod)>GCD?0:GCD;
}
int solve(int A,int B,int P,int C){
	int pw=Pow(P,C),Phi=(P-1)*Pow(P,C-1);
	B%=pw;
	if (B==0)
		return Pow(P,C-((C+A-1)/A));
	int g=gcd(B,pw),Q=0;
	B/=g;
	while (g>1)
		g/=P,Q++;
	return Pow(P,Q-Q/A)*((Q%A)?0:RHD(A,B,P,C-Q));
}
int main(){
	Get_Prime(1e5);
	int T=read();
	while (T--){
		int A=read(),B=read(),P=2*read()+1;
		int cnt,p[50],q[50];
		Divide(P,p,q,cnt);
		int ans=1;
		for (int i=1;i<=cnt;i++)
			ans*=solve(A,B,p[i],q[i]);
		printf("%d\n",ans);
	}
	return 0;
}

 

  

 

posted @ 2018-09-09 16:40  zzd233  阅读(303)  评论(0编辑  收藏  举报