高大上的数论,先入门再说。
原根的定义可以到wiki上找,上面介绍得很清楚。
如果你是个热(bu)爱(dong)祖(ying)国(yu)的人,看这个blog就行了
1、51nod 1135
奇怪的oj,还是放链接吧
求奇素数n最小的原根。
从2~n-1枚举x,判断x是否满足x^j mod n != 1 j=2,3,4,...,phi(n)-1
暴力判断会T,需要跟快的算法。
wiki介绍了一个方法。
设phi(n)=p1^k1*p2^k2......pm^km
那么x是n的一个原根充要条件为
x^(phi(n)/pj) mod n != 1 j = 1,2,3...m
证明:
若存在j使得x^(phi(n)/pj) mod n = 1,不必说,x不是原根
如不存在j满足条件,假设t满足x^t mod n = 1
那么x^(phi(n)-t) mod n =1
由辗转相除算法可知x^gcd(phi(n),t) mod n = 1
令d = gcd(phi(n),t), 即x^d mod n = 1
因为d|phi(n),所以至少有一个j满足d|phi(n)/pj,不妨设其为i
所以x^(phi(n)/pj) mod n = 1,与假设矛盾,得证
回归原题,由于n为素数,所以phi(n)=n-1,分解n-1后对每个pj检查一下即可
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int prime[100000]; bool check[100000]; int P,i,cnt,tot,p[1000]; void init(){ for (int i=2;i<100000;i++){ if (!check[i]) prime[++tot]=i; for (int j=1;j<=tot;j++){ if (i*prime[j]>=100000) break; check[i*prime[j]]=true; if (i%prime[j]==0) break; } } } int qck(int a,int b){ int ret = 1; for (;b>0;b>>=1){ if (b&1) ret=(long long)ret*a%P; a = (long long)a*a%P; } return ret; } bool Judge(int x){ for (int i=1;i<=cnt;i++) if (qck(x,(P-1)/p[i])==1) return 0; return 1; } void Analyze(int x){ cnt = 0; for (int i=1;i<tot;i++) if (x%prime[i]==0) p[++cnt] = prime[i]; } int main(){ //freopen("1135.in","r",stdin); //freopen("1135.out","w",stdout); init(); while (~scanf("%d",&P)){ Analyze(P-1); for (i=2;i<P;i++) if (Judge(i)) break; printf("%d\n",i); } return 0; }
求一个奇素数的原根数量。
wiki上给了一个定理:如果n有原根,那么n的原根数量为phi( phi(n) )
n有原根的充要条件是n可以写成以下形式中的一种:2,4,p^k,2*p^k 其中p为奇素数
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n,tot; int prime[100000]; int phi[100000]; bool check[100000]; void init(){ phi[1] = 1; for (int i=2;i<100000;i++){ if (check[i]==0){ prime[++tot] = i; phi[i] = i-1; } for (int j=1;j<=tot;j++){ if (i*prime[j]>=100000) break; check[i*prime[j]]=1; if (i%prime[j]==0){ phi[i*prime[j]] = phi[i]*prime[j]; break; } else phi[i*prime[j]] = phi[i]*(prime[j]-1); } } } int main(){ freopen("poj1284.in","r",stdin); freopen("poj1284.out","w",stdout); init(); while (~scanf("%d",&n)) printf("%d\n",phi[n-1]); return 0; }