BZOJ2219 数论之神【同余拆分+原根指标+BSGS+拓展欧几里得 求解的个数/ 数论大礼包】

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/C20181220_xiang_m_y/article/details/102654321

题目描述:

给出 A , B 1 0 9 , K 5 1 0 8 A,B\le10^9,K\le5*10^8 ,求 x A B   ( m o d   2 K + 1 ) , x [ 0 , 2 K ] x^A\equiv B~(mod~2K+1),x\in[0,2K] 的整数解的个数。

题目分析:

这个题解明明超详细却打错几个公式

Code:

#include<bits/stdc++.h>
using namespace std;
int T,A,B,K;
inline int Pow(int a,int b){
	int s=1;
	for(;b;b>>=1,a*=a) b&1&&(s*=a);
	return s;
}
inline int Pow(int a,int b,const int p){
	int s=1;
	for(;b;b>>=1,a=1ll*a*a%p) b&1&&(s=1ll*s*a%p);
	return s;
}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int G_Primeroot(int P,int phi){
	static int pr[100005],cnt,tmp; cnt=0,tmp=phi;
	for(int i=2;i*i<=tmp;i++) if(tmp%i==0) {pr[++cnt]=i;while(tmp%i==0) tmp/=i;}
	if(tmp>1) pr[++cnt]=tmp;
	for(int g=2;;g++) if(Pow(g,phi,P)==1){
		for(int i=1;i<=cnt;i++) if(Pow(g,phi/pr[i],P)==1) goto no;
		return g; no:;
	}
}
inline int BSGS(int a,int b,int p){
	if(b==1) return 0;
	static map<int,int>vis; vis.clear();
	int base=1,now=1,t=b,m=sqrt(p)+1;
	for(int i=0;i<m;i++) vis[t]=i,t=1ll*t*a%p,base=1ll*base*a%p;
	for(int i=1;i<=m;i++) if(vis.count(now=1ll*now*base%p)) return i*m-vis[now];
}
int solve(int p,int a,int b){
	int s=0;while(b%p==0) b/=p,s++;
	if(s>=a) return Pow(p,a-(a+A-1)/A);
	if(s){
		if(s%A) return 0;
		return solve(p,a-s,b)*Pow(p,s-s/A);
	}
	int real=Pow(p,a),phi=(p-1)*Pow(p,a-1);
	int I=BSGS(G_Primeroot(real,phi),b%real,real),d=gcd(A,phi);
	if(I%d) return 0; return d;
}
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d",&A,&B,&K);
		int tmp=2*K+1,s,ans=1;
		for(int i=2;i*i<=tmp;i++) if(tmp%i==0) {s=0;while(tmp%i==0) s++,tmp/=i;ans*=solve(i,s,B);}
		if(tmp>1) ans*=solve(tmp,1,B);
		printf("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/102654321