ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-02-18 21:03:47  阅读:153  来源: 互联网

标签:return 原根 51nod hs int 1038 ans equiv MOD


题目

\(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;
}

标签:return,原根,51nod,hs,int,1038,ans,equiv,MOD
来源: https://www.cnblogs.com/Spare-No-Effort/p/15911224.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有