原根结论记录

定义

两个数 a,m,其中满足 ap1(modm) 的最小 pφ(m) 时,称 am 的一个原根。

结论

  • 一个数有原根当且仅当他是形如 2,4,pk,2×pk(其中 p 是奇素数)
  • 一个数 n 的原根个数为 φ(φ(n))
  • 设一个数的最小原根为 g,则其所有原根都可以表示为 gk(其中 gcd(k,φ(n))=1

实现

首先寻找最小的原根,而最小的原根的充要条件有下面两个:

  • gφ(m)1(modm)
  • φ(m) 是最小的满足 gp1(modm)p,那么这个的判断方法就是求出 φ(m) 的所有质因子 p1pk,判断对于任意的 i 是否满足 gφ(m)pi1(modm)

代码实现

Code
#include<bits/stdc++.h>
using namespace std;
inline long long read()
{
  long long x=0,f=1;char ch=getchar();
  while(!isdigit(ch)&&ch!='-')ch=getchar();
  if(ch=='-')f=-1,ch=getchar();
  while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  return x*f;
}
bool exist[2001010],flag,vis[2001010];
long long prim[2001010],tn,j,up,len,final[2001010];
long long i,n,gap,tem,w,down,now,phi[2001010],factor[2001010];
long long pow(long long x,long long y,long long p){
	long long ans=1;
	for (;y;y>>=1,x=x*x % p)
	    if (y&1) ans=ans*x % p;
	return ans;
}
void Main(){
	n=read();gap=read();
	if (exist[n]==false) {puts("0");puts("");return ;}
	printf("%lld\n",phi[phi[n]]);
	tem=phi[n];w=0;
	for (i=2;i<=sqrt(phi[n]);i++)
	    if (tem % i==0){
	    	factor[++w]=i;
	    	while (tem % i==0) tem/=i;
		}
	if (tem>1) factor[++w]=tem;
	down=0;
	for (now=1;now<n;now++)
	    if (pow(now,phi[n],n)==1){
	    	flag=true;
	    	for (j=1;j<=w;j++)
	    	    if (pow(now,phi[n]/factor[j],n)==1)
	    	        flag=false;
	    	if (flag){
	    		down=now;break;
			}
		}
	tn=0;now=1;
    for (up=1;up<=phi[n];up++){
    	now=now*down % n;
    	if (__gcd(up,phi[n])==1) final[++tn]=now;
	}
	sort(final+1,final+tn+1);
	for (i=1;i<=tn/gap;i++) printf("%lld ",final[i*gap]);
	puts("");
}
int main()
{
	int Testing=read();up=1e6;
	phi[1]=1;
	for (int i=2;i<=up;i++){
		if (vis[i]==false) {
			phi[i]=i-1;
			prim[++len]=i;
		}
		for (j=1;j<=len&&i*prim[j]<=up;j++){
			vis[i*prim[j]]=true;
			phi[i*prim[j]]=phi[i]*phi[prim[j]];
			if (i % prim[j]==0) {
				phi[i*prim[j]]=phi[i]*prim[j];
				break; 
			}
		}
	}
	exist[2]=exist[4]=true;
	for (i=2;i<=len;i++)
	   for (j=prim[i];j<=up;j=j*prim[i])  {
	   	exist[j]=true;
	   	if (j*2<=up) exist[j*2]=true;
	   }
	for (;Testing;Testing--) Main(); 
return 0;
}
posted @   OIer_Albedo  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示