数论-原根

原根与阶

定义

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

性质

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

求解

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

代码

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4992

#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; 
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值