原根和阶 及模板

原根和阶及模板

小记:

摆出定义和算法 ⇒ \Rightarrow 解释算法

主要参考 算法导论第31章 和传送门1

原根的定义

o r d n ( g ) = ϕ ( n ) ord_n(g)=\phi(n) ordn(g)=ϕ(n), 即g对模n的阶等于n的欧拉函数,则g是n的原根。

如果g是n的原根,则对于 Z n ∗ Z_n^{*} Zn的任意一个元素,都存在z,使得 g z ≡ a ( m o d n ) g^z \equiv a(mod n) gza(modn)

什么样的N有原根

如果N=2,4, p e , 2 p e p^e ,2p^e pe2pe(p是大于2的质数,e是正整数),则N有原根

原根的意义?

如果 Z n ∗ Z_n^{*} Zn包含一个原根,就称 Z n ∗ Z_n^{*} Zn是循环的。

求N的原根的算法步骤

step1: 将N的欧拉函数phi进行质因数分解,phi(N)= ϕ ( N ) \phi(N) ϕ(N)=$ p_1^{a_1} *p_2{a_2}*……p_n{a_n}$

step2: 枚举i,判断每个i是否有 i k i^{k} ik mod N = = 1 的 最 小 k 是 不 是 ==1的最小k是不是 ==1k ϕ ( N ) p i \frac{\phi(N)}{p_i} piϕ(N) ,符合条件的就是N的最小原根

step3:利用最小原根得到 其他原根,

​ 其他原根的形式都为 g k g^k%N gk形式,且gcd(k, ϕ ( N ) \phi(N) ϕ(N))=1

基础知识 🥛


1.模运算

Z n Z_n Zn={0,1,……,n-1}

Z n ∗ Z_n^{*} Zn={ a ∈ Z n a\in Z_n aZn 且 gcd(a,n)=1}​

比如 Z 15 ∗ Z_{15}^{*} Z15={1, 2, 4, 7, 8, 11, 13, 14}

2. ϕ ( n ) \phi(n) ϕ(n)是什么?

Z n ∗ Z_n^{*} Zn的规模就是欧拉函数, ∣ Z n ∗ ∣ = ϕ ( n ) = n ∗ ∏ p i 是 素 数 且 p i ∣ n ( 1 − 1 p ) |Z_n^{*}|= \phi(n)=n*\prod_{p_i是素数且p_i|n}(1-\frac{1}{p}) Zn=ϕ(n)=npipin(1p1)

比如 ϕ ( 15 ) = 8 \phi(15)=8 ϕ15=8

3.ord()是什么?

a通过(自定义运算 a^k%n,k为正整数)得到有限群。

一个元素的阶等于它所生成子群的规模,即 ord(a)=|<a>|

也是 满足 a k % n = 1 a^{k}\%n=1 ak%n=1的最小正整数k。

举例如下

n=7时, Z 7 ∗ Z_7^{*} Z7={1,2,3,4,5,6}

n=70123456
2 i % n 2^i\%n 2i%n1242412
3 i % n 3^i\%n 3i%n1326451

如 n=7,i=2时,<a>={1,2,4}, a 3 = 1 a^3=1 a3=1, |a|=3

​ n=7, i=3时,<a>={1,3,2,6,4,5}, a 6 = 1 a^6=1 a6=1, |a|=6

​ 发现了吗?这时<a>与 Z 7 ∗ Z_7^{*} Z7同,故3是7的原根

4.欧拉定理

如果n是正整数且 a ∈ Z n ∗ a\in Z_n^{*} aZn, 那么 a ϕ ( n ) % n = 1 a^{\phi(n)}\%n=1 aϕn)%n=1

算法解释

那么回到原根定义, o r d n ( g ) = ϕ ( n ) ord_n(g)=\phi(n) ordn(g)=ϕ(n)

欧拉函数很好求,而g要怎么寻找呢?

我们采用枚举i的方式,对每个i,

看使它为 i^k %n=1的最小正整数k是不是 ϕ ( n ) \phi(n) ϕn

并且如果 i ∈ Z n ∗ i\in Z_n^{*} iZn ,那么由 欧拉定理 得到$ i^{\phi(n)}%n=1$,如果不属于的话,我们还要去计算证明一下。

那难道要用 i k i^k ik,k ∈ \in [1, ϕ ( n ) \phi(n) ϕ(n)) 去检查吗?

不用,只需要枚举 i ϕ ( N ) p i i^{\frac{\phi(N)}{p_i}} ipiϕ(N) %n去就行,

原因是k 分为2部分,不能被 ϕ ( n ) \phi(n) ϕ(n)整除的,和能被 ϕ ( n ) \phi(n) ϕ(n)整除的。

对于不能被 ϕ ( n ) \phi(n) ϕ(n)整除部分

关于不能被 ϕ ( n ) \phi(n) ϕ(n)整除,

使用结论, i g % m o d = 1 i^g\%mod=1 ig%mod=1,则对于任意不满足c | g的数不存在 i c % m o d = 1 i^c\%mod=1 ic%mod=1,可以直接pass。

证明:

使 用 反 证 法 使用反证法 使
假 设 存 在 不 满 足 c ∣ g 使   i c %   m o d = 1 , 且 c 1 是 最 小 的 c 假设存在不满足c|g使\,i^{c}\%\,mod=1,且c_1是最小的c cg使ic%mod=1,c1c
∴ i c 1   %   m o d = 1 ,   c 2 = g − c 1 \therefore i^{c_1}\,\%\,mod=1,\,c_2=g-c_1 ic1%mod=1,c2=gc1
∵ i g % m o d = 1 , 我 们 在 前 面 已 经 确 认 过 \because i^g\%mod=1,我们在前面已经确认过 ig%mod=1,
∴ ( i c 1 % m o d ) ∗ ( i c 2 % m o d ) = 1 \therefore(i^{c_1}\%mod)*(i^{c_2}\%mod)=1 (ic1%mod)(ic2%mod)=1
∴ i c 2 % m o d = 1 \therefore i^{c_2}\%mod=1 ic2%mod=1
如果 c_1|c_2,则 g = c 1 + c 2 = ( 1 + f ) c 1 g=c_1+c_2=(1+f)c_1 g=c1+c2=(1+f)c1,与假设条件相矛盾
∴ g c d ( c 1 , c 2 ) < c 1 \therefore gcd(c1,c2)<c_1 gcd(c1,c2)<c1
∵ \because i c 2 − c 1 ≡ i c 2 ∗ ( i c 1 ) − 1 ≡ 1 ( % m o d ) i^{c_2-c_1}\equiv i^{c_2}*(i^{c_1})^{-1}\equiv1(\% mod) ic2c1ic2(ic1)11(%mod) ∴ \therefore 由gcd的更相减损术原理得 i g c d ( c 2 , c 1 ) i^{gcd(c_2,c_1)} igcd(c2,c1)%mod=1
又 ∵ g c d ( c 1 , c 2 ) < c 1 与 原 假 设 c 1 是 最 小 相 矛 盾 又\because gcd(c1,c2)<c1 与原假设c_1是最小相矛盾 gcd(c1,c2)<c1c1
∴ 假 设 不 成 立 , 故 若 i g % m o d = 1 , 不 满 足 c ∣ g , 则 不 能 使 得 i c % m o d = 1 \therefore 假设不成立,故若 i^g\%mod=1,不满足c|g,则不能使得i^c\%mod=1 ig%mod=1cg使ic%mod=1

对于能被 ϕ ( n ) \phi(n) ϕ(n)整除部分

ϕ ( n ) \phi(n) ϕn进行质因数分解,得到 ϕ ( n ) = p 1 a 1 ∗ p 2 a 2 ∗ … … \phi(n)=p_1^{a_1}*p_2^{a_2}*…… ϕn)=p1a1p2a2

只要 i p d % n ≠ 1 i^{p_d}\% n\neq 1 ipd%n=1,

那么如果 i p d ∗ … … i p d ⏟ ϕ ( n ) p d ≠ 1 \underbrace{i^{p_d}*……i^{p_d}}_{\frac{\phi(n)}{p_d}} \neq1 pdϕ(n) ipdipd=1,即只要证 i ϕ ( N ) p d i^{\frac{\phi(N)}{p_d}} ipdϕ(N) %n$\neq$1即可

代码

(hdu4492模板)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10,inf=0x3f3f3f3f;
int n,fac[N],nf;
vector<int> ans;
int Pow(int x,int p,int mod) {
    int ret=1;
    for(; p; p>>=1,x=(ll)x*x%mod)if(p&1)ret=(ll)ret*x%mod;
    return ret;
}
int phi(int x) {        //求欧拉函数
    int ret=x;
    for(int i=2; i<=x/i; ++i)if(x%i==0) {
            ret=ret/i*(i-1);
            while (x%i==0)x/=i;
        }
    if(x>1)ret=ret/x*(x-1);
    return ret;
}
void getfac(int x) {
    //得到x的质因数
    nf=0;
    for(int i=2; i<=x/i; ++i)if(x%i==0)
            for(fac[nf++]=i; x%i==0; x/=i);
    if(x>1)fac[nf++]=x;
}
bool is_have_root(int x) {
    //如果N=2,4,p^e ,2*(p^e)(p是大于2的质数,e是正整数),则N有原根
    if(x==2||x==4)return 1;
    if(x%4==0)return 0;
    if(x%2==0)x/=2;
    for(int i=3; i*i<=x; ++i)if(x%i==0) {
            for(; x%i==0; x/=i);
            return x==1;
        }
    return 1;
}
int minRoot(int x,int phix) {
    //求最小原根
    if(x==2||x==4)return x-1;
    for(int i=2; i<x; ++i)if(Pow(i,phix,x)==1) {
            bool flag=1;
            for(int j=0; j<nf; ++j)if(Pow(i,phix/fac[j],x)==1) {flag=0; break;}
            if(flag)return i;
        }
}
void solve(int x) {
    int phix=phi(x);        //得到x的欧拉函数
    getfac(phix);            //得到phi(x)的质因数
    int r=minRoot(x,phix);     //得到最小原根
    ans.clear(),ans.push_back(r);
    for(int i=2; i<phix; ++i)if(__gcd(i,phix)==1)ans.push_back(Pow(r,i,x));  //用最小原根得到其它原根
    sort(ans.begin(),ans.end());
}
int main() {
//    freopen("in.text","r",stdin);
    while(scanf("%d",&n)==1) {
        if(!is_have_root(n))puts("-1");
        else {
            solve(n);
            for(int i=0; i<ans.size(); ++i)printf("%d%c",ans[i]," \n"[i==ans.size()-1]);
        }
    }
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是Mally呀!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值