原根结论记录

定义

两个数 \(a,m\),其中满足 \(a^{p}\equiv 1\pmod m\) 的最小 \(p\)\(\varphi(m)\) 时,称 \(a\)\(m\) 的一个原根。

结论

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

实现

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

  • \(g^{\varphi(m)}\equiv 1\pmod m\)
  • \(\varphi(m)\) 是最小的满足 \(g^{p} \equiv 1 \pmod m\)\(p\),那么这个的判断方法就是求出 \(\varphi(m)\) 的所有质因子 \(p_1\sim p_k\),判断对于任意的 \(i\) 是否满足 \(g^{\frac{\varphi(m)}{p_i}} \not \equiv 1 \pmod m\)

代码实现

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 @ 2022-11-16 19:45  OIer_Albedo  阅读(43)  评论(0)    收藏  举报