[学习笔记]原根

[学习笔记]原根

前言

这里只是简要概述一下,我也不会证明,防止忘记。

一些定义

1.欧拉定理

\[a^{\varphi(m)}\equiv 1 \bmod m,a\perp m \]

2. 阶

满足 \(a^n\equiv1\bmod m\) 的最小正整数 \(n\) 称为 a 模 m 的阶 ,记作 \(\delta_m(a)\).

于是有恒等式 \(a^{\delta_m(a)}\equiv1\bmod m\)

3.原根

\[m\in N^+,a\in Z,a\perp m,\delta_m(a)=\varphi(m) \]

同时满足这四个条件的称 a 为 m 的原根。

容易知道可以将所有 a 映射到 \([1,m-1]\)
并且原根还有一个重要的性质:

\[a^0,a^1,a^2,a^3.....a^{\varphi(p)-1}\bmod p,互不相等 \]

阶的性质

性质1

\[a^n\equiv1\bmod m\Rightarrow \delta_m(a)|n \]

性质2

\(\delta_m\) 是一个积性函数

性质3

\[a\perp m \Rightarrow\delta_m(a^k)=\frac{\delta_ma}{gcd(\delta_ma,k)} \]

关于原根的定理

原根的分布

有且仅有1,2,4,奇素数的正整数幂和幂的两倍有原根

原根的判断

对于一个 \(a\) 满足 \(a\perp m\)

\[\forall p|\varphi(m),a^{\frac{\varphi(m)}{p}}\not\equiv 1\bmod m \]

那么a是m的一个原根

原根的扩散

基于一个最小的原根 g 可以得出其他所有的原根。那些原根\(g'\)满足

\[g'\equiv g^x\bmod m , x\in(1,\varphi(m))且x\perp \varphi(m) \]

CODE

Luogu 的模板而已

const int MAXN=1e6+5;
bool has[MAXN],isp[MAXN];
int prime[MAXN],t,n,d,pphi[MAXN],ans[MAXN];
inline int get_phi(int x){
	int res=x;
	pphi[0]=0;
	for(int i=1;prime[i]*prime[i]<=x;++i){
		if(x%prime[i]==0)res=res/prime[i]*(prime[i]-1);
		while(x%prime[i]==0)x/=prime[i];
	} 
	if(x>1)res=res/x*(x-1);
	for(int i=1;prime[i]<=res;++i)if(res%prime[i]==0)pphi[++pphi[0]]=prime[i];
	return res;
}
inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline int ksm(int a,int b,int mod){
	int res=1;
	for(;b;b>>=1,a=(a*a)%mod)if(b&1)res=(res*a)%mod;
	return res;
}
signed main(){
	has[1]=has[2]=has[4]=1;
	fe(i,2,MAXN){
		if(!isp[i])prime[++prime[0]]=i;
		for(int j=1;j<=prime[0]&&prime[j]*i<MAXN;++j){
			isp[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
	}
	fe(i,2,prime[0]){
		int po=prime[i];
		while(po<MAXN){
			has[po]=1;
			if(po*2<MAXN)has[po*2]=1;
			po*=prime[i];
		}
	}
	t=read();
	while(t--){
		n=read(),d=read();
		ans[0]=0;
		if(!has[n]){puts("0"),puts("");continue;}
		int phi=get_phi(n);
		int g;
		for(g=1;g<=phi;++g)if(gcd(g,n)==1){
			int fl=0;
			fe(j,1,pphi[0])if(ksm(g,phi/pphi[j],n)==1){
				fl=1;break;
			}if(!fl)break;
		}
		int base=g;
		for(int x=1;x<=phi;++x,g=(g*base)%n)if(gcd(x,phi)==1)ans[++ans[0]]=g;
		sort(ans+1,ans+ans[0]+1);
		printf("%lld\n",ans[0]);
		for(int i=d;i<=ans[0];i+=d)printf("%lld ",ans[i]);
		printf("\n");
	}
	return 0;
}
posted @ 2021-01-07 17:01  clockwhite  阅读(200)  评论(0编辑  收藏  举报