HDU4992-原根
Posted 水明
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于HDU4992-原根的主要内容,如果未能解决你的问题,请参考以下文章
原根二连 HDU 4992 && poj 1284 Primitive Roots
HDU 6051 If the starlight never fade(原根+推式子)
2^x mod n = 1 HDU - 1395(欧拉定理 原根)
bzoj千题计划210:bzoj2642 | Poj3968 | UVALive 4992| hdu 3761 Jungle Outpost