Java教程

#原根,BSGS,扩欧#51nod 1038 X^A Mod P

本文主要是介绍#原根,BSGS,扩欧#51nod 1038 X^A Mod P,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

题目

\(T(T\leq 100)\) 组询问在模 \(P\) 意义下给 \(B\) 开 \(A\) 次方根,

求出 \([0,P)\) 的所有解,\(P\) 是一个质数。


分析

求出 \(P\) 的原根 \(G\),若 \(G^x\equiv B\pmod{P}\),这个 \(x\) 可以通过 BSGS 求出来。

那么 \(X^A\equiv B\pmod{P}\) 就可以转换成 \(G^{kA}\equiv G^x\pmod{P}\)

其中 \(G^k\equiv X\pmod{P}\),那么 \(kA\equiv x\pmod{P-1}\)

用扩欧求出来 \(k\) 的所有解再带进去 \(G^k\) 算出所有的 \(X\)


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int MOD=70001;
struct Linked_Hash{
	struct node{int y,w,next;}E[MOD]; int Et,hs[MOD];
	void Clear(){Et=0,memset(hs,-1,sizeof(hs));}
	void Insert(int w,int x){E[++Et]=(node){x,w,hs[w%MOD]},hs[w%MOD]=Et;}
	int locate(int W){
		for (int i=hs[W%MOD];~i;i=E[i].next)
		    if (E[i].w==W) return E[i].y;
		return -1;
	}
}ha;
int p,phi,P[MOD],ToT,g,a,m,ans[MOD],tot,prime[MOD],v[MOD],Cnt;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
void FJ(int p){
	for (int i=1;prime[i]*prime[i]<=p;++i)
	if (p%prime[i]==0){
		P[++ToT]=prime[i];
		while (p%prime[i]==0) p/=prime[i];
	}
	if (p>1) P[++ToT]=p;
}
int ksm(int x,int y,int p){
	int ans=1;
	for (;y;y>>=1,x=1ll*x*x%p)
	    if (y&1) ans=1ll*ans*x%p;
	return ans;
}
bool check(int x,int p){
	if (ksm(x,phi,p)!=1) return 0;
	for (int i=1;i<=ToT;++i)
	if (ksm(x,phi/P[i],p)==1) return 0;
	return 1;
}
int Mn_Rt(int p){
	for (int i=1;i<p;++i)
	if (check(i,p)) return i;
	return -1;
}
int BSGS(int a,int b,int mod){
	ha.Clear();
	int ir=sqrt(mod)+1,now=1;
	for (int i=0;i<ir;++i)
	    ha.Insert(1ll*now*b%mod,i),now=1ll*now*a%mod;
	a=now,now=1;
	if (!a) return !b?1:-1;
	for (int i=0;i<=ir;++i){
		int j=ha.locate(now);
		if (j>=0&&i*ir>=j) return i*ir-j;
		now=1ll*now*a%mod;
	}
	return -1;
}
int exgcd(int a,int b,int &x,int &y){
	if (!b) {x=1,y=0; return a;}
	int Gcd=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return Gcd;
}
int main(){
	for (int i=2;i<MOD;++i){
		if (!v[i]) prime[++Cnt]=i;
		for (int j=1;j<=Cnt&&prime[j]<=MOD/i;++j){
			v[i*prime[j]]=1;
			if (i%prime[j]==0) break;
		}
	}
	for (int Test=iut();Test;--Test){
		ToT=tot=0,p=iut(),a=iut(),m=iut(),FJ(phi=p-1),g=Mn_Rt(p);
		int b=phi,x,y,c=BSGS(g,m,p),Gcd=exgcd(a,b,x,y);
		if (c%Gcd) printf("No Solution\n");
		else{
			x=(1ll*x*(c/Gcd)%phi+phi)%phi;
			for (int i=1;i<=Gcd;++i)
				x=(x+b/Gcd)%phi,ans[++tot]=ksm(g,x,p);
			sort(ans+1,ans+1+tot),tot=unique(ans+1,ans+1+tot)-ans-1;
			for (int i=1;i<=tot;++i) print(ans[i]),putchar(i==tot?10:32);
		}
	}
	return 0;
}
这篇关于#原根,BSGS,扩欧#51nod 1038 X^A Mod P的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!