【数论数学】原根与阶

56 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【数论数学】原根与阶

定义

设 a,m 两数互质,满足 a^x^≡1(mod m) 的最小的 x,称为 a 对 m 的阶,记为 ordm(a)。
当 ordm(a)=ϕ(m) 时称为 a 为 m 的一个原根。

性质

  1. ax1ordm(a)xa^x≡1⇔ord_m(a)∣x
  2. ordm(a)ϕ(m)ord_m(a)∣ϕ(m)
  3. n有原根⇔n2,4,pe,2pen∈{2,4,p^e,2*p^e}(p为奇素数)
  4. 一个数的最小原根的大小不超过 m14m^{\frac{1}{4}}
  5. 若g是m的一个原根,那么g^d^是m的原根的充分必要条件是gcd(d,Φ(m))=1,由此可推知一个数的原根个数为Φ(Φ(m))个
  6. ordm(ad)=ordm(a)ordm(a),dord_{m}(a^{d})=\frac{ ord_m(a) }{ ord_m(a),d }(利用这个性质可以求出所有原根)
  7. a0,a1,,aordm(a)1a^0,a^1,…,a^{ord_m(a)−1} 构成摸m的既约剩余系
  8. axaya^x≡a^y(mod m)xy(modordm(a))⇔x≡y(mod ord_m(a))
  9. ϕ(m)=p1r1p2r2pKrkϕ(m)=p_1^{r1}p_2^{r2}…p_K^{rk},则g是m的原根⇔对与所有的pi,gϕ(m)pi1g^{\frac{ϕ(m)}{p_i}}≠1(mod m)

求解

  1. 判断一个数是否有原根。(枚举质数)
  2. 求得最小原根。(依次枚举2m142~ m^{\frac14} 判断)
  3. 求出所有原根。(枚举次数d)

代码

题目链接

acm.hdu.edu.cn/showproblem…

代码

#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <vector>  
#include <algorithm>  
using namespace std; 
const int N=1000000; 
bool f[1000000]; 
int phi(int x)
{  
    if (f[x])  return x-1; 
    int ans=x; 
    for (int i=2;i<=x;i++)
        if (x%i==0)
		{  
            while (x%i==0) x/=i; 
            ans=ans-ans/i; 
        }
    return x>1?ans-ans/x:ans; 
}  
int gcd(int a,int b)
{  
    swap(a,b); 
    int c=a%b; 
    while (c) a=b,b=c,c=a%b;
    return b;
}  
int quick_mod(int x,int p,int mod)
{  
    long long s=1,a=x; 
    while (p)
	{  
        if (p&1) s=(s*a)%mod; 
        a=a*a%mod,p>>=1; 
    }
    return (int)s; 
}  
vector<int> V,G; 
void cal(int x)
{  
    G.clear(); 
    if (f[x]) return; 
    else for (int i=2;i*i<=x;i++)
        if (x%i==0)
		{  
            G.push_back(i); 
            if (i*i!=x) G.push_back(x/i); 
        }
}  
bool exist(int n)
{  
    if (n%2==0)  n/=2; 
    if (f[n])    return 1; 
    for (int i=3;i*i<=n;i+=2){  
        if (n%i==0){  
            while (n%i==0)   n/=i; 
            return n==1; 
        }  
    }  
    return 0; 
}  
bool solve(int n)
{  
    if (n==4||n==2) return printf("%d\n",n-1),0;
    if (!exist(n)) return printf("-1\n");
    int p=phi(n),x=-1; 
    cal(p);
    for (int i=2;i<n;i++)
        if (quick_mod(i,p,n)==1)
        {
        	bool flag=1;
        	for (int j=0;j<G.size()&&flag;j++)
          	    if (quick_mod(i,G[j],n)==1) flag=0;
       		if (flag)
			{  
            	V.resize(1),V[0]=x=i; 
            	break; 
        	}  
		}  
    if (x==-1) return printf("-1\n"),0;
    for (int i=2;i<p;i++)
        if (gcd(i,p)==1) V.push_back(quick_mod(x,i,n)); 
    sort(V.begin(),V.end()); 
    vector<int>::iterator it=unique(V.begin(),V.end()); 
    V.erase(it,V.end()); 
    for (int i=0;i<V.size();i++)
	{
		if (i) printf(" ");
		printf("%d",V[i]);
	}
    return printf("\n"),0;
}  
int main()
{  
    memset(f,1,sizeof(f)); 
    f[0]=f[1]=0; 
    for (int i=2;i<1000000;i++)
        if (f[i])
            for (int j=i<<1;j<1000000;j+=i) f[j]=0;
    int n; 
    while (~scanf("%d",&n)) solve(n); 
    return 0; 
}