一、原根
原根的概念
原根是一种数学符号,设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的欧拉函数)
定义1 :(a模n的阶乘),设
和
是互素的整数,
。使得
成立的最小的正整数
被称为
模
的阶,并记作
。
定义2 :(原根),设 和 是互素的整数, 。如果 ,则称 是模 的原根,并称 有一个原根。
例如,设
。
所以 是模 的两个原根, 不是模 的原根。
如何判断一个数 是不是 模 m下的原根呢?
先对 质因子分解,即 。若恒有 成立,那么 就是 的原根。
【例题1 】POJ1284 Primitive Roots (积性函数)
题意:
给一个奇素数
内的数
分别
,正好是
,可以不按顺序,求满足这个式子的
的个数
思路:
本质就是求原根的个数,而求原根数有一个公式 原根数=phi(phi(m))
又由于给的数m是奇素数,所以phi[m] = m - 1;
所以答案就是phi[m-1]
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
const int N = 7e4;
int phi[N];
int m;
void get_phi(int n){
for(int i = 2; i <= n; i++) phi[i] = i;
for(int i = 2; i <= n; i++){
if(phi[i] == i){
for(int j = i; j <= n; j += i){
phi[j] = phi[j] / i * (i - 1);
}
}
}
}
int main(){
get_phi(N-1);
while(scanf("%d",&x\m) != EOF){
printf("%d\n",phi[m-1]);
}
return 0;
}
【例题2】51Nod 1135 原根
题意
设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的欧拉函数)
给出1个质数P,找出P最小的原根。
思路
求模素数
的原根的方法:对
素因子分解,即
。若恒有
成立,那么
就是
的原根(对于合数而言,只需要把
换成
即可)
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e5 + 7;
int prime[N],prime_tot = 0,tot = 0,p[N];
bool prime_tag[N];
int n;
//素数筛法
void get_prime() {
for(int i = 2; i < N; i++) prime_tag[i] = true;
for(int i = 2; i < N; i++) {
for(ll j = 1ll * i * i; j < N; j += i) {
prime_tag[j] = false;
}
}
for(int i = 2; i < N; i++)
if(prime_tag[i]) prime[prime_tot++] = i;
}
//快速幂
ll qpow(ll a, ll b, ll mod) {
ll res = 1;
while(b) {
if(b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
//分解质因子
void divide(int n) {
tot = 0;
for(int i = 0; i < prime_tot; i++) {
if(n % prime[i] == 0) {
//printf("%d ",prime[i]);
p[tot++] = prime[i];
while(n % prime[i] == 0 && n > 1) {
n /= prime[i];
}
}
if(n == 1) break;
}
}
//判断是不是原根
bool check(int x) {
for(int i = 0; i < tot; i++){
if(qpow(x,(n-1)/p[i],n) == 1) return false;
}
return true;
}
int main() {
get_prime();
scanf("%d",&n);
divide(n - 1);
for(int i = 2; i < n; i++) {
if(check(i)) {
printf("%d\n",i);
break;
}
}
return 0;
}
二、离散对数
离散对数的概念
如果模
有一个原根
,则
组成模
的一个简化剩余系(1~m中和m互质的元素集合)。也就是说对于任一个整数
,都可以唯一地表示为
设 是模 的一个原根,对于任一整数 ,都有 ,我们把 称为以 为底的 对模 的离散对数,记为 。离散对数也称为指标。
之所以称为离散对数,是因为它定义在离散的整数集合上,而不是象普通对数那样定义在连续的实数集合上。
例如,已知模 的一个原根是 ,以 为底模 的离散对数。
对于实数对数,我们通常 两边同时取log,这样就可以将幂次变成多项式,在离散对数中,做了这样的变换后,模m则变成了模φ(m)。于是我们就可以将一些乘法操作变成加法操作,来简化或者解决一些运算问题.
一些重要性质