1.原根定义

假设一个数g对于P来说是原根,那么g^i mod P的结果两两不同,且有 1<g<P, 1<i<P,那么g可以称为是P的一个原根
简单来说,g^i mod p ≠ g^j mod p (p为素数)
其中i≠j且i, j介於1至(p-1)之间
则g为p的原根。
简单的来说,如果g是P的原根,那么g的(1...P-1)次幂mod P的结果一定互不相同。
那么简化一下:
首先看一下欧拉定理:

欧拉定理(也称费马-欧拉定理欧拉函数定理)是一个关于同余的性质。欧拉定理表明,若为正整数,且互素(即),则

因此,在时,定义对模的指数为使成立的最小的正整数。由前知 一定小于等于 ,若,则称是模的原根
归根到底,如果g是P的原根,就是g^(P-1) = 1 (mod P)当且仅当指数为P-1的时候成立.(这里P是素数).
例如:
m= 7,则φ(7)等于6。φ(7)表示7的欧拉函数。
a= 2,由于2^3=8≡1(mod 7),而3<6,所以 2 不是模 7 的一个原根。设a= 3,由于3^1≡3(mod 7),3^2≡2(mod 7),3^3≡6(mod 7),3^4≡4(mod 7),3^5≡5(mod 7),3^6≡1(mod 7),所以 3 是模 7 的一个原根。

2.如何求解:

一、枚举

从2开始枚举,然后暴力判断g^(P-1) = 1 (mod P)是否当且当指数为P-1的时候成立

而由于原根一般都不大,所以可以暴力得到.

二、讲究方法

例如求任何一个质数x的任何一个原根,一般就是枚举2到x-1,并检验。有一个方便的方法就是,求出x-1所有不同的质因子p1,p2...pm,对于任何2<=a<=x-1,判定a是否为x的原根,只需要检验a^((x-1)/p1),a^((x-1)/p2),...a^((x-1)/pm)这m个数中,是否存在一个数mod x为1,若存在,a不是x的原根,否则就是x的原根。

原来的复杂度是O(P-1),现在变成O(m)*log(P-1)m为x-1质因子的个数。很明显质因子的个数远远小于x-1。

证明可用欧拉定理和裴蜀定理:

裴蜀定理

说明了对任何整数a、b和它们的最大公约数d,关于未知数x和y的线性丢番图方程(称为裴蜀等式):

ax + by = m 
有解当且仅当m是d的倍数。裴蜀等式有解时必然有无穷多个整数解,每组解x、y都称为裴蜀数,可用辗转相除法求得。

例如,12和42的最大公因子是6,则方程12x + 42y = 6有解。事实上有(-3)×12 + 1×42 = 6及4×12 + (-1)×42 = 6。

特别来说,方程 ax + by = 1 有解当且仅当整数a和b互素。

裴蜀等式也可以用来给最大公约数定义:d其实就是最小的可以写成ax + by形式的正整数。这个定义的本质是整环中“理想”的概念。因此对于多项式整环也有相应的裴蜀定理。

证明

[html] view plaincopy
  1. 若存在,那么显然的事情
  2. 否则,假设存在一个t<phi(x)=x-1使得a^t = 1 (mod x)
  3. 那么由裴蜀定理,一定存在一组k,r使得kt=(x-1)r+gcd(t,x-1)
  4. 而由欧拉定理有,a^(x-1) = 1 (mod x)
  5. 于是1 = a^(kt) = a^(xr-r+gcd(t,x-1)) = a^gcd(t,x-1) (mod x)
  6. 而t<x-1故gcd(t,x-1)<x-1
  7. 又gcd(t,x-1)|x-1 于是gcd(t,x-1)必整除(x-1)/p1,(x-1)/p2...(x-1)/pm其中至少一个,设其一为(x-1)/pi
  8. 那么a^((x-1)/pi) = (a^gcd(t,x-1))^s = 1^s = 1 (mod x)
  9. 这与假设矛盾

代码:

来至http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1135的一道题目:

题目

设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的欧拉函数)

给出1个质数P,找出P最小的原根。
Input
<span id="Showjim86_bnbbbsbl_s39"></span>输入1个质数P(3 <= P <= 10^9)<span id="Showjim86_bnbbbsbl_e39"></span>
Output
<span id="Showjim86_bnbbbsbl_s40"></span>输出P最小的原根。

解答

[cpp] view plaincopy
  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cstdio>
  5. using namespace std;
  6. int P;
  7. const int NUM = 32170;
  8. int prime[NUM/4];
  9. bool f[NUM];
  10. int pNum = 0;
  11. void getPrime()//线性筛选素数
  12. {
  13. for (int i = 2; i < NUM; ++ i)
  14. {
  15. if (!f[i])
  16. {
  17. f[i] = 1;
  18. prime[pNum++] = i;
  19. }
  20. for (int j = 0; j < pNum && i*prime[j] < NUM; ++ j)
  21. {
  22. f[i*prime[j]] = 1;
  23. if (i%prime[j] == 0)
  24. {
  25. break;
  26. }
  27. }
  28. }
  29. }
  30. __int64 getProduct(int a,int b,int P)//快速求次幂mod
  31. {
  32. __int64 ans = 1;
  33. __int64 tmp = a;
  34. while (b)
  35. {
  36. if (b&1)
  37. {
  38. ans = ans*tmp%P;
  39. }
  40. tmp = tmp*tmp%P;
  41. b>>=1;
  42. }
  43. return ans;
  44. }
  45. bool judge(int num)//求num的所有的质因子
  46. {
  47. int elem[1000];
  48. int elemNum = 0;
  49. int k = P - 1;
  50. for (int i = 0; i < pNum; ++ i)
  51. {
  52. bool flag = false;
  53. while (!(k%prime[i]))
  54. {
  55. flag = true;
  56. k /= prime[i];
  57. }
  58. if (flag)
  59. {
  60. elem[elemNum ++] = prime[i];
  61. }
  62. if (k==1)
  63. {
  64. break;
  65. }
  66. if (k/prime[i]<prime[i])
  67. {
  68. elem[elemNum ++] = prime[i];
  69. break;
  70. }
  71. }
  72. bool flag = true;
  73. for (int i = 0; i < elemNum; ++ i)
  74. {
  75. if (getProduct(num,(P-1)/elem[i],P) == 1)
  76. {
  77. flag = false;
  78. break;
  79. }
  80. }
  81. return flag;
  82. }
  83. int main()
  84. {
  85. getPrime();
  86. while (cin >> P)
  87. {
  88. for (int i = 2;;++i)
  89. {
  90. if (judge(i))
  91. {
  92. cout << i<< endl;
  93. break;
  94. }
  95. }
  96. }
  97. return 0;
  98. }

原根(详解+代码实现+例题+快速求解一个数的原根)相关推荐

  1. 原根-快速求解一个数的原根

    1.原根定义 假设一个数g对于P来说是原根,那么g^i mod P的结果两两不同,且有 1<g<P, 1<i<P,那么g可以称为是P的一个原根 简单来说,g^i mod p ≠ ...

  2. SpringBoot详解(一)-快速入门

    SpringBoot详解系列文章: SpringBoot详解(一)-快速入门 SpringBoot详解(二)-Spring Boot的核心 SpringBoot详解(三)-Spring Boot的we ...

  3. .user.ini上传详解附CTF例题

    .user.ini上传详解附CTF例题 题目 解法 https://buuoj.cn/challenges#[SUCTF%202019]CheckIn [SUCTF 2019]CheckIn 题目 解 ...

  4. 五分钟搞懂后缀数组!后缀数组解析以及应用(附详解代码)

    为什么学后缀数组 后缀数组是一个比较强大的处理字符串的算法,是有关字符串的基础算法,所以必须掌握. 学会后缀自动机(SAM)就不用学后缀数组(SA)了?不,虽然SAM看起来更为强大和全面,但是有些SA ...

  5. 腐烂国度2怎么学计算机知识,腐烂国度2操作方法详解 教你如何快速掌握操作方法...

    腐烂国度2操作方法详解 教你如何快速掌握操作方法 很多小伙伴买了腐烂国度2不知道怎么玩,刚上手连操作按键在哪都不知道.下面小编就为大家带来了腐烂国度2操作方法详解 教你如何快速掌握操作方法. 基本操作 ...

  6. 『ML笔记』HOG特征提取原理详解+代码

    HOG特征提取原理详解+代码! 文章目录 一. HOG特征介绍 二. HOG算法具体流程+代码 2.1. 图像灰度化和gamma矫正 2.2. 计算图像像素梯度图 2.3. 在8×8的网格中计算梯度直 ...

  7. 24.shell中list详解,定义list,获取List的总个数,获取list的某个元素值,将list的每个元素转换成以空格分隔的字符串,空格分隔的字符串转换成list,for循环list

    文章目录 前言 定义list 获取List的总个数 获取list的某个元素值 将list的每个元素转换成以空格分隔的字符串 空格分隔的字符串转换成list for循环list 总结 友情链接 前言 s ...

  8. [学习笔记] 伸展树splay详解+全套模板+例题[Luogu P3369 【模板】普通平衡树]

    文章目录 引入概念 全套模板 变量声明 update ==rotate旋转== splay操作 insert插入 delete删除 查找x的位置 查找第k大 前驱/后继 极小值-inf和极大值inf的 ...

  9. xvid 详解 代码分析 编译等

    1.   Xvid参数详解 众所周知,Mencoder以其极高的压缩速率和不错的画质赢得了很多朋友的认同! 原来用Mencoder压缩Xvid的AVI都是使用Xvid编码器的默认设置,现在我来给大家冲 ...

最新文章

  1. 【数据平台】Eclipse+MapReduce开发环境(集群运行模式)
  2. [Elasticsearch] 邻近匹配 (二) - 多值字段,邻近程度与相关度
  3. 数据结构-栈之二进制转十进制和八进制
  4. java制作五子棋的论文,基于java的五子棋的设计与实现.docx
  5. java 获取发布后的路径问题_Java中的路径问题实例分析
  6. Two-Stream RNN/CNN for Action Recognition in 3D Videos-阅读笔记
  7. 定个小目标,炒股咯....
  8. excel两个表格数据对比_Excel表格技巧—如何统计数据个数
  9. Robocopy命令实现文件服务器每日镜像备份/增量备份操作
  10. 【杂谈】Windows安装Fluent Terminal
  11. 抖音旋转很炫的html,火爆抖音的旋转时钟屏保,超酷超炫的
  12. 《计算机网络》在物理层和数据链路层扩展以太网
  13. 如何快速合并PDF文件?几个方法教你合并PDF
  14. 考试试卷用什么纸打印,哪里打印试卷便宜
  15. 解决无法设置默认打开方式
  16. ROS到ROS2的多节点组合运行
  17. 编译工具 Ninja 介绍
  18. 软件开发,如何快速有效缩短项目周期
  19. 【人工智能】3.谓词与机器推理
  20. win10系统,点击连接校园网WLAN后,弹不出登录网页

热门文章

  1. 现代软件工程 第八章 【需求分析】练习与讨论
  2. java数组有跨类建立对象_必会的 55 个 Java 性能优化细节!一网打尽!
  3. Linux基本目录结构
  4. JAVA入门级教学之(参数传递)
  5. JAVA入门级教学之(if语句)
  6. python指定条件分类输出_python基础(二)条件判断、循环、格式化输出
  7. 程序员的数学 pdf_作为一个程序员,分享我日常学习方式,自学渠道和方式
  8. linux 状态码的意义,HTTP状态码是什么?常见的状态码描述都有什么?
  9. python3环境运行python2代码_使用Anaconda实现Python2和Python3共存及相互转换
  10. tensorflowgpu利用率为0_直流电压利用率的提高方法-梯形波调制法