原根

定义

数论,特别是整除理论中,原根是一个很重要的概念。

对于两个正整数 (a,m)=1, 由欧拉定理可知,存在正整数d\leq m-1, 比如说欧拉函数d=\varphi (m),即小于等于m的正整数中与m互素的正整数的个数,使得 a^{d}\equiv 1{\pmod  {m}}

由此,在(a,m)=1时,定义a对模m的指数    \delta m(a)    为使  a^{d}\equiv 1{\pmod  {m}}  成立的最小的正整数  d  。由前知  \delta m(a)   一定小于等于  \varphi (m)  ,若  \delta m(a) = \varphi (m)  ,则称   a 是模 m 的原根。

 

例子

设 m=7  ,则  \varphi (m)  等于6。

  • 设  a=2  ,由于  2^{3}=8\equiv 1{\pmod  {7}}     ,而  \displaystyle 3<6  ,所以 2 不是模 7 的一个原根。
  • 设  a=3  ,由于  3^{1}\equiv 3{\pmod  {7}}  , 3^{2}\equiv 2{\pmod  {7}}  , 3^{3}\equiv 6{\pmod  {7}}  , 3^{4}\equiv 4{\pmod  {7}}  , 3^{5}\equiv 5{\pmod  {7}}  , 3^{6}\equiv 1{\pmod  {7}}  ,因此有 Ord_{7}(3)=6=\varphi (7)  ,所以 3 是模 7 的一个原根。

性质

  • 可以证明,如果正整数 (a,m)=1  和正整数 d 满足 a^{d}\equiv 1{\pmod  {m}},则  Ord_{m}(a) 整除 d。因此 Ord_{m}(a) 整除 \varphi (m) 。在例子中,当 a=3 时,我们仅需要验证 3 的 2、3 次方模 7 的余数即可,如果其中有一个是1,则3就不是原根。
  • 记 \delta =Ord_{m}(a)  ,则 a^{0},a^{1},a^{2}\cdots ,a^{​{\delta -1}} 模 m 两两不同余。因此当a是模{\displaystyle m}m的原根时, a^{0},a^{1},a^{2}\cdots ,a^{​{\delta -1}}  构成模 m 的简化剩余系
  • 模 m 有原根的充要条件是 m=2,4,p^{n},2p^{n} ,其中 p 是奇素数, n 是任意正整数
  • 对正整数 (a,m)=1 ,如果 a 是模 m 的原根,那么 a 是整数模m乘法群(即加法群 Z/mZ 的可逆元,也就是所有与 m 互素的正整数构成的等价类构成的乘法群)Zm×的一个生成元。由于Zm×有  \varphi (m) 个元素,而它的生成元的个数就是它的可逆元个数,即 \varphi (\varphi (m)) 个,因此当模 m 有原根时,它有 \varphi (\varphi (m)) 个原根。

一些数的原根列表

m模m的原根(有*号的数没有原根,此时是有最大模m周期的数)周期 (OEISA002322)
101
211
322
432
52, 3, 44
652
73, 56
8*3, 5, 72
92, 56
103, 74
112, 6, 7, 810
12*5, 7, 112
132, 6, 7, 1112
143, 56
15*2, 7, 8, 134
16*3, 5, 11, 134
173, 5, 6, 7, 10, 11, 12, 1416
185, 116
192, 3, 10, 13, 14, 1518
20*3, 7, 13, 174
21*2, 5, 10, 11, 17, 196
227, 13, 17, 1910
235, 7, 10, 11, 14, 15, 17, 19, 20, 2122
24*5, 7, 11, 13, 17, 19, 232
252, 3, 8, 12, 13, 17, 22, 2320
267, 11, 15, 1912
272, 5, 11, 14, 20, 2318
28*3, 5, 11, 17, 19, 236
292, 3, 8, 10, 11, 14, 15, 18, 19, 21, 26, 2728
30*7, 13, 17, 234
313, 11, 12, 13, 17, 21, 22, 2430
32*3, 5, 11, 13, 19, 21, 27, 298
33*2, 5, 7, 8, 13, 14, 17, 19, 20, 26, 28, 2910
343, 5, 7, 11, 23, 27, 29, 3116
35*2, 3, 12, 17, 18, 23, 32, 3312
36*5, 7, 11, 23, 29, 316

除了直接运算以外,至今还没有一个办法可以找到模特定m时的原根,但假如已知模m有一个原根,则可找出它其他的原根。

 

题目一:求最小的原根

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int Maxn = 1e6+10;
const int N = 1e8+10;
int prime[Maxn];//存储素数
int sprime[Maxn];//存储P-1的素因子
bool check[Maxn];
bitset<Maxn>pri;//结果只有0和1,判断是否为素数
int k;//记录Maxn以内的素数个数
int cnt;//记录素因子的个数
void is_prime(){
    pri.set();//将所有的二进制数都标为1
    for(int i=2; i<Maxn; i++) {
        if(pri[i]) {
            prime[k++]=i;
            for(int j=i+i; j<Maxn; j+=i)
                pri[j]=0;
        }
    }
}
void Divide(int n)//将n分解为素因子
{
    cnt=0;
    int t=(int)sqrt(1.0*n);
    for(int i=0; prime[i]<=t; i++) {
        if(n%prime[i]==0) {
            sprime[cnt++]=prime[i];
            while(n%prime[i]==0)//因为有可能有多个peime[i]
                n/=prime[i];
        }
    }
    if(n>1)
        sprime[cnt++]=n;//可能只有自己一个素因子
}
LL modexp(LL a,LL b,int mod)//快速幂取余
{
    LL res=1;
    while(b>0) {
        a=a%mod;
        if(b&1)
            res=res*a%mod;
        b=b>>1;
        a=a*a%mod;
    }
    return res;
}

int main()
{
    int p;
    Is_prime();
    while(~scanf("%d",&p)) {
        Divide(p-1);
        for(int g=2; g<p; g++) {
            int flag=1;
            for(int i=0; i<cnt; i++) {
                int t=(p-1)/sprime[i];
                if(modexp(g,t,p)==1) {
                    flag=0;
                    break;
                }
            }
            if(flag) {
                int root=g;
                printf("%d\n",root);
                break;//去掉break的话是求所有的原根,加上break是求最小的原根、
            }
        }
    }
    return 0;
}

 

题目二:求原根的个数

#include<bits/stdc++.h>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))

typedef long long ll;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9+7;

ll n;
ll get(ll n){
    ll ans = n;
    for(int i=2;i*i<=n;i++){
        if(n %i == 0){
            ans = ans / i * (i - 1);
            while(n %i == 0)
                n /= i;
        }
    }
    if(n > 1)   ans = ans / n * (n - 1);
    return ans ;
}
int main(){
    while(scanf("%lld",&n)!=EOF){
        printf("%lld\n",get(get(n)));
    }
    return 0;
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值