HDU4992-原根

题意

给出一个数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;
}

 

posted @ 2017-11-11 05:32  水明  阅读(358)  评论(0编辑  收藏  举报