【学习笔记】原根

原根是 NTT 的前置,想学 NTT 就得先学求原根。
由于作者个人时间原因,原根直接讲结论。

 
只有2,4,pc,2×pc有原根,其中 c 为奇质数。
n 的原根大概在 n0.25 左右,且分布密集。
检测 p 是否是原根,要看对于所有的 ϕ(n) 的质数 k,是否都有 pϕ(n)k1。(理解是除了 pϕ(n) 其他的次方都不能等于1,而pϕ(n)包含了所有的因数。)
找到最小原根 p 后(复杂度 n0.25logϕ(n)),可以通过 pk (gcd(k,ϕ(n))==1) 求出所有的原根。原根总个数为 ϕ(ϕ(n))

 
luogu模板题代码。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=10000010,Ma=1e6;
int mod;
int wk[N],zhi[N],tail;
int n,d,fi,ans[N],cnt;
int sum[N],tot;
bool had[N];
int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
int pw(int x,int y){
	int ansn=1;
	while(y){
		if(y&1)ansn=ansn*x%mod;
		x=x*x%mod,y/=2;
	}
	return ansn;
}
void work(){
	n=rd(),d=rd(),cnt=tot=0;
	if(!had[n])return printf("0\n\n"),void();
	mod=n;
	fi=n;
	for(int i=1;i<=tail&&zhi[i]<=n;i++)if(n%zhi[i]==0)fi=fi*(zhi[i]-1)/zhi[i];
	for(int i=1;i<=tail&&zhi[i]<=fi;i++)if(fi%zhi[i]==0)sum[++tot]=zhi[i];
	int gen;
	for(gen=1;gen<n;gen++){
		if(gcd(gen,n)!=1)continue;
		bool flg=true;
		for(int i=1;i<=tot;i++){
			if(pw(gen,fi/sum[i])==1)flg=false;
		}
		if(flg)break;
	}
	for(int i=1,j=gen;i<=fi;i++,j=j*gen%mod){
		if(gcd(i,fi)==1)ans[++cnt]=j;
	}
	sort(ans+1,ans+cnt+1);
	printf("%lld\n",cnt);
	for(int i=d;i<=cnt;i+=d)printf("%d ",ans[i]);
	printf("\n");
	return ;
}
signed main(){
	for(int i=2;i<=Ma;i++){
		if(!wk[i])zhi[++tail]=i;
		for(int j=1;j<=tail&&i*zhi[j]<=Ma;j++){
			wk[zhi[j]*i]=true;
			if(i%zhi[j]==0)break;
		}
	}
	had[2]=had[4]=true;
	for(int i=2;i<=tail;i++){
		for(int j=1;j*zhi[i]<=Ma;j=j*zhi[i])had[j*zhi[i]]=true;
		for(int j=2;j*zhi[i]<=Ma;j=j*zhi[i])had[j*zhi[i]]=true;
	}
	int T=rd();
	while(T--)work();
	return 0;
}
/*
1
36 1
*/
posted @   flywatre  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示