原根

\(gcd(a,m)=1\) ,使 \(a^l \equiv 1 (mod\ m)\) 成立的最小的 \(l\) ,称为 \(a\) 关于模 \(m\) 的阶

\(a\) 关于模 \(m\) 的阶为 \(l\),则 \(a^t\) 关于模 \(m\) 的阶 \(\frac{l}{gcd(t,l)}\)

原根

\(a\) 关于模 \(m\) 的阶为 \(\varphi(m)\) ,则称 \(a\)\(m\) 的一个原根

  1. \(m\) 存在原根的充分必要条件是 \(m\) 的形式如 \(2,4,p^k,2p^k\)\(p\) 为质数
  2. \(m\) 的原根的个数为 \(\varphi(\varphi(m))\)
  3. 已知 \(m\) 的最小原根为 \(a\) ,那么 \(m\) 的原根就如 \(a^k\) 之类的,满足 \(k\)\(\varphi(a)\) 互质

求解原根

  • 先判断原根存不存在

  • 求解最小的原根

  • 求解所有的原根

原根的应用

更新中

洛谷模板题

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1000010;
int t,p,cnt,tot,ctans,fc[maxn],ans[maxn],pri[maxn],rt[maxn],q[maxn],phi[maxn];
void init(){// 欧拉筛 + 原根筛
	phi[1]=1;
	for(int i=2;i<=maxn-10;++i){
		if(!q[i]){
			pri[++tot]=i,phi[i]=i-1;
		}
		for(int j=1;j<=tot&&pri[j]*i<=maxn-10;++j){
			q[i*pri[j]]=1;
			if(i%pri[j]==0){
				phi[i*pri[j]]=phi[i]*pri[j];
				break;
			}
			phi[i*pri[j]]=phi[i]*(pri[j]-1);
		}
	}
	rt[2]=rt[4]=1;
	for(int i=2;i<=tot;++i){
		for(int j=1;(1ll*j*pri[i])<=maxn-10;j*=pri[i]){
			rt[j*pri[i]]=1;
		}
		for(int j=2;(1ll*j*pri[i])<=maxn-10;j*=pri[i]){
			rt[j*pri[i]]=1;
		}
	}
	return;
}
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
int pow(int a,int b,int p){
	int res=1;
	while(b){
		if(b&1)res=(1ll*res*a)%p;
		a=(1ll*a*a)%p;
		b>>=1;
	}
	return res;
}
void proc(int p){// 数字分解
	for(int i=2;i*i<=p;i++){
		if(p%i==0){
			fc[++cnt]=i;
			while(p%i==0)p/=i;
		}
	}
	if(p>1)fc[++cnt]=p;
	return;
}
bool chk(int x,int p){// 判断 x 是不是 p 的一个原根
	if(pow(x,phi[p],p)!=1)return 0;
	for(int i=1;i<=cnt;++i){
		if(pow(x,phi[p]/fc[i],p)==1)return 0;
	}
	return 1;
}
int findrt(int p){ // 求最小的原根
	for(int i=1;i<p;++i){
		if(chk(i,p))return i;
	}
	return 0;
}
void getrt(int p,int x){// 已知最小的原根,求解对于整数 p 的所有原根
	int prod=1;
	for (int i=1;i<=phi[p];i++) {
		prod=(1ll*prod*x)%p;
		if (gcd(i,phi[p])==1) {
			ans[++ctans]=prod;
		}
	}
	return;
}
int main (){
	init();
	scanf("%d",&t);
	while(t--){
		int wtf;
		scanf("%d%d",&p,&wtf);
		if(rt[p]){
			ctans=cnt=0;
			proc(phi[p]);
			int mn=findrt(p);
			getrt(p,mn);
			sort(ans+1,ans+ctans+1);
			printf("%d\n",ctans); 
			for(int i=1;i<=ctans/wtf;++i)
				printf("%d ",ans[i*wtf]);
			printf("\n");
		} 
		else printf("0\n\n");
	}
	return 0;
}
posted @ 2020-07-09 08:10  VagrantAC  阅读(148)  评论(0编辑  收藏  举报