题意
给出一个数n满足$2\leqslant n\leqslant1000000$,求n的所有原根
分析
n有原根的充要条件是$n=2,4,p^x\,or\,2p^x$.其中p是素数,x任意是正整数
如果r是n的一个原根,则$r^x$也是n的原根,x满足$(x,\phi(n))=1$.
所以如果n有原根,则n有$\phi(\phi(n))$个原根
如果知道n的一个原根r,则可以在$O(\phi n)$时间内求出n的所有原根
那怎么求n的一个原根呢
根据原根定义暴力试试
r和n互素且$r^x\equiv 1(mod\,n)$成立的最小正整数x满足$x=\phi(n)$
从2到n-1枚举r
首先判定$r^{\phi(n)}=1(mod\,n)$
然后对于每一个$\phi(n)$的素因子d,判定$r^{\phi(n)/d}\neq 1(mod\,n)$
通过这两个条件的r就是n的一个原根了
代码
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=1000001;
int m[N],phi[N],p[N],tot,prime[N];
//m[i]是i的最小素因数
void initPhi(){
phi[1]=1;
int k;
for(int i=2;i<N;i++){
if(!m[i]){
p[tot++]=m[i]=i;
prime[i]=1;
phi[i]=i-1;
}
for(int j=0;j<tot&&(k=p[j]*i)<N;j++){
m[k]=p[j];
if(m[i]==p[j]){
phi[k]=phi[i]*p[j];break;
}
else phi[k]=phi[i]*(p[j]-1);
}
}
}
int root[N]={0};
void initRoot(){
root[2]=root[4]=1;
//从第二个质数3开始
for(int i=1;i<tot;i++){
for(LL j=p[i];j<N;j*=p[i]){
root[j]=1;
}
for(LL j=2*p[i];j<N;j*=p[i]){
root[j]=2;
}
}
}
vector<int> getfac(int n){
vector<int>fac;
LL tmp=n;
for(int i=0;tmp>1&&i<tot;i++){
if(tmp%p[i]==0){
fac.push_back(p[i]);
while(tmp%p[i]==0)tmp/=p[i];
}
}
if(tmp>1)fac.push_back(tmp);
return fac;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int ans[N],ia;
//已知n的一个原根x求n的所有phi(phi(n))个原根
void getRoot(int n,int x){
ia=0;
ans[ia++]=x;
int y=x;
for(int i=2;i<phi[n];i++){
y=(y*x)%n;
if(gcd(i,phi[n])==1)ans[ia++]=y;
}
sort(ans,ans+ia);
}
LL pow_mod(LL a,LL b,LL p){
LL ret=1;
while(b){
if(b&1)ret=(ret*a)%p;
a=(a*a)%p;
b>>=1;
}
return ret;
}
//求n的一个原根
int oneRoot(int n){
vector<int> fac=getfac(phi[n]);
for(int i=1;i<n;i++){
int flag=1;
if(pow_mod(i,phi[n],n)!=1)flag=0;
else
for(int j=0;j<fac.size();j++){
if(pow_mod(i,phi[n]/fac[j],n)==1){
flag=0;
break;
}
}
if(flag)return i;
}
return 0;
}
void getRoot(int n){
if(n==1||n==2||n==3)printf("%d\n",n-1);
else if(root[n]){
getRoot(n,oneRoot(n));
for(int i=0;i<ia;i++){
if(i)printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
else printf("-1\n");
}
int main(){
initPhi();
initRoot();
int n;
while(~scanf("%d",&n)){
getRoot(n);
}
return 0;
}