原根结论记录
定义
两个数 \(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;
}

浙公网安备 33010602011771号