zoukankan      html  css  js  c++  java
  • HDU4992-原根

    题意

    给出一个数n满足$2leqslant nleqslant1000000$,求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^xequiv 1(mod\,n)$成立的最小正整数x满足$x=phi(n)$

    从2到n-1枚举r

    首先判定$r^{phi(n)}=1(mod\,n)$

    然后对于每一个$phi(n)$的素因子d,判定$r^{phi(n)/d} eq 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-1);
    	else if(root[n]){
    		getRoot(n,oneRoot(n));
    		for(int i=0;i<ia;i++){
    			if(i)printf(" ");
    			printf("%d",ans[i]);
    		}
    		printf("
    ");
    	}
    	else printf("-1
    ");
    }
    int main(){
    	initPhi();
    	initRoot();
    	int n;
    	while(~scanf("%d",&n)){
    		getRoot(n);
    	}
        return 0;
    }
    
  • 相关阅读:
    hdu1852 Beijing 2008
    hdu-2582 f(n)---找规律+素数筛法
    hdu-1452 Happy 2004---因子和+逆元
    LightOJ-1028 Trailing Zeroes (I)---因子数目
    hdu1215 七夕节---因子和
    因子和&&因子数
    hdu-1492 The number of divisors(约数) about Humble Numbers---因子数公式
    hdu-2136 Largest prime factor---巧用素数筛法
    欧拉函数
    BZOJ4418: [Shoi2013]扇形面积并
  • 原文地址:https://www.cnblogs.com/shuiming/p/7818021.html
Copyright © 2011-2022 走看看