ICode9

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

原根

2022-09-11 17:02:29  阅读:213  来源: 互联网

标签:1000010 原根 text ord include equiv


我也不知道为什么我求原根的板子都没打就来学ntt(

好吧其实知道原根是啥就行

定义:若 \(\gcd(a,n)=1\) ,则满足 \(a^{x}\equiv 1 \pmod n\) 的最小正整数 \(x\) 称为 \(a\) 模 \(n\) 的阶,记作 \(\text{ord}_n(a)\) 。

性质:

  1. \(a,a^2,a^3,\cdots,a^{\text{ord}_n(a)}\) 在模 \(n\) 意义下两两不同。(所以ntt用原根替代单位根)
  2. 若 \(a^x\equiv 1 \pmod n\) ,则 \(\text{ord}_n(a)\mid x\) 。
    一个推论:若 \(a^p\equiv a^q \pmod n\) ,则 \(p\equiv q \pmod {\text{ord}_n(a)}\) 。
  3. 阶是积性函数。
  4. \(\text{ord}_n(a^k)=\frac{\text{ord}_n(a)}{\gcd(\text{ord}_n(a),k)}\)

原根

如果 \(\text{ord}_n(a)=\varphi(n)\) ,则 \(a\) 为模 \(n\) 的原根。

只有 \(1,2,4,p^k,2p^k\) 有原根( \(p\) 是奇素数, \(k\) 是任意正整数)。

原根的判定:设 \(m\ge 3\) ,则 \(a\) 是模 \(n\) 的原根的充要条件是对 \(\varphi(n)\) 的每个质因数 \(p\) ,有 \(a^{\frac {\varphi(n)}p}\not\equiv 1\pmod n\) 。

然后一个数的最小原根是 \(n^{0.25}\) 级别的,所以可以暴力找。

然后如果找到了一个数的最小原根 \(g\) ,则所有满足 \(\gcd(k,\varphi(n))\) 的\(g^k\) 都是模 \(n\) 的原根。

最后来一个洛谷求原根的板子。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define int long long
int n,d,g[1000010],phi[1000010],p[1000010],prm[1000010];
bool v[1000010],rt[1000010];
void get(){
	phi[1]=1;
	for(int i=2;i<=1000000;i++){
		if(!v[i]){
			p[++p[0]]=i;phi[i]=i-1;
		}
		for(int j=1;j<=p[0]&&i*p[j]<=1000000;j++){
			v[i*p[j]]=true;
			if(i%p[j]==0){
				phi[i*p[j]]=phi[i]*p[j];break;
			}
			phi[i*p[j]]=phi[i]*phi[p[j]];
		}
	}
	rt[2]=rt[4]=true;
	for(int i=2;i<=p[0];i++){
		for(int j=p[i];j<=1000000;j=j*p[i])rt[j]=true;
		for(int j=p[i]*2;j<=1000000;j=j*p[i])rt[j]=true;
	}
}
int getphi(int x){
	int ans=x;
	for(int i=2;i*i<=x;i++){
		if(x%i==0){
			ans=ans/i*(i-1);
			while(x%i==0)x/=i;
		}
	}
	if(x!=1)ans=ans/x*(x-1);
	return ans;
}
void getp(int x){
	for(int i=2;i*i<=x;i++){
		if(x%i==0){
			prm[++prm[0]]=i;
			while(x%i==0)x/=i;
		}
	}
	if(x!=1)prm[++prm[0]]=x;
}
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=1ll*ans*a%n;
		a=1ll*a*a%n;
		b>>=1;
	}
	return ans;
}
bool check(int x){
	if(qpow(x,phi[n])!=1)return false;
	for(int i=1;i<=prm[0];i++){
		if(qpow(x,phi[n]/prm[i])==1)return false;
	}
	return true;
}
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
signed main(){
	int tim;scanf("%lld",&tim);
	get();
	while(tim--){
		scanf("%lld%lld",&n,&d);
		if(!rt[n]){
			printf("0\n\n");
		}
		else{
			prm[0]=g[0]=0;
			getp(phi[n]);
			int ret;
			for(int i=1;i<n;i++){
				if(check(i)){
					ret=i;break;
				}
			}
			for(int i=1;i<=phi[n];i++){
				if(gcd(i,phi[n])==1)g[++g[0]]=qpow(ret,i);
			}
			sort(g+1,g+g[0]+1);
			printf("%lld\n",g[0]);
			for(int i=d;i<=g[0];i+=d)printf("%lld ",g[i]);
			printf("\n");
		}
	}
}

标签:1000010,原根,text,ord,include,equiv
来源: https://www.cnblogs.com/gtm1514/p/16684358.html

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

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

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

ICode9版权所有