阶
阶:由欧拉定理可知,对于a∈za\in\mathbb{z}a∈z,m∈N∗m\in\mathbb{N}^{*}m∈N∗,若gcd(a,m)=1\gcd(a,m)=1gcd(a,m)=1,则aφ(m)≡1(modm)a^{\varphi(m)}\equiv 1\pmod maφ(m)≡1(modm)。
因此满足同余式an≡1(modm)a^n\equiv 1 \pmod man≡1(modm)的最小整数nnn存在,这个n称作aaa模mmm的阶,记作δm(a)\delta_m(a)δm(a)。
性质1:a,a2,⋯ ,aδm(a)a,a^2,\cdots,a^{\delta_m(a)}a,a2,⋯,aδm(a)模mmm两两不同余
性质2:an≡1(modm)a^n\equiv 1\pmod man≡1(modm),则δm(a)∣n\delta_m(a)\mid nδm(a)∣n。
性质3:设m∈N∗m\in\mathbb{N}^{*}m∈N∗,a,b∈za,b\in\mathbb{z}a,b∈z,gcd(a,m)=gcd(b,m)=1\gcd(a,m)=\gcd(b,m)=1gcd(a,m)=gcd(b,m)=1,则δm(ab)=δm(a)δm(b)\delta_m(ab)=\delta_m(a)\delta_m(b)δm(ab)=δm(a)δm(b)的充分必要条件是gcd(δm(a),δm(b))=1\gcd(\delta_m(a),\delta_m(b))=1gcd(δm(a),δm(b))=1
性质4:设k∈Nk\in\mathbb{N}k∈N,m∈N∗m\in\mathbb{N}^{*}m∈N∗,a∈za\in\mathbb{z}a∈z,gcd(a,m)=1\gcd(a,m)=1gcd(a,m)=1,则δm(ak)=δm(a)gcd((δm(a),k)\delta_m(a^k)=\dfrac{\delta_m(a)}{gcd\big(\big(\delta_m(a),k\big)}δm(ak)=gcd((δm(a),k)δm(a)
原根
原根:设m∈N∗m\in\mathbb{N}^{*}m∈N∗,a∈za\in\mathbb{z}a∈z,若gcd(a,m)=1\gcd(a,m)=1gcd(a,m)=1,且δm(a)=φ(m)\delta_m(a)=\varphi(m)δm(a)=φ(m),则称aaa为模mmm的原根。
原根判定定理
原根判定定理:设m⩾3,gcd(a,m)=1m \geqslant 3,\gcd(a,m)=1m⩾3,gcd(a,m)=1,则aaa是模mmm的原根的充要条件,对于φ(m)\varphi(m)φ(m)的每个素因数ppp,都有aφ(m)p≢1(modm)a^{\frac{\varphi(m)}{p}}\not\equiv 1\pmod mapφ(m)≡1(modm)。
原根个数
若一个数mmm有原根,则它原根的个数为φ(φ(m))\varphi(\varphi(m))φ(φ(m))。
原根存在定理
原根存在定理:一个数mmm存在原根当且仅当m=2,4,pα,2pαm=2,4,p^{\alpha},2p^{\alpha}m=2,4,pα,2pα,其中ppp为奇素数,α∈N∗\alpha\in \mathbb{N}^{*}α∈N∗。
定理1:对于奇素数ppp,ppp有原根。
定理2:对于奇素数ppp,α∈N∗\alpha \in \mathbb{N}^{*}α∈N∗,pαp^\alphapα有原根。
定理3:对于奇素数ppp,α∈N∗\alpha \in \mathbb{N}^{*}α∈N∗,2pα2p^\alpha2pα有原根。
定理4 :对于m≠2,4m\ne 2,4m=2,4,且不存在奇素数ppp及α∈N∗\alpha \in \mathbb{N}^{*}α∈N∗使得m=pα,2pαm=p^\alpha,2p^\alpham=pα,2pα, 模mmm的原根不存在。
总结
根据欧拉定理我们可以知道,若a,ma,ma,m互质,aφ(m)≡1(modm)a^{\varphi(m)}\equiv 1 \pmod maφ(m)≡1(modm)。因此,a1,a2,...a^1,a^2,...a1,a2,...这样一个数列在模mmm意义下将有一个φ(m)\varphi(m)φ(m)长度的循环节,因为aφ(m)+1a^{\varphi(m)+1}aφ(m)+1又回到了一开始的a1a^1a1。
然而,我们并不能保证它是最短的循环节,例如,21≡2,22≡4,23≡1(mod7)2^1\equiv 2,2^2\equiv4,2^3\equiv 1 \pmod 721≡2,22≡4,23≡1(mod7),可以发现这时候最短循环节长度为333,而不是φ(7)=6\varphi(7)=6φ(7)=6。我们把这个最短循环节的长度定义为aaa在模mmm下的阶,记住δm(a)\delta_m(a)δm(a)。严格地,定义aaa在模mmm下的阶是同余方程ax≡1(modm)a^x\equiv 1\pmod max≡1(modm)的最小正整数解。
显然,δm(a)\delta_m(a)δm(a)一定是φ(m)\varphi(m)φ(m)的因数。特别地,当δm(a)=φ(m)\delta_m(a)=\varphi(m)δm(a)=φ(m),就称aaa为模mmm下的一个原根,对于原根aaa来说,a1,a2,...,aφ(m)a^1,a^2,...,a^{\varphi(m)}a1,a2,...,aφ(m)在模mmm下各不相同,他们就是最短的循环节。
求解nnn的所有原根的步骤为:
1.预处理
-
线性筛出不大于 mmm 的素数,并求出所有不大于mmm的正整数的欧拉函数值。
-
对每个不大于mmm的素数ppp,求出所有不大于mmm的pαp^\alphapα和 2pα2p^\alpha2pα。(原根存在定理)
2.判定nnn是否有原根
3.求最小原根
- 求出φ(m)\varphi(m)φ(m)的所有因质数
- 枚举与mmm互质的iii(原根定义)
- 对于φ(m)\varphi(m)φ(m)的每个质因数jjj,分别计算iφ(m)ji^{{\frac{\varphi(m)}{j}}}ijφ(m),如果iφ(m)j≡1(modm)i^{{\frac{\varphi(m)}{j}}} \equiv1\pmod{m}ijφ(m)≡1(modm)说明iii不是原根(原根判定定理)
- 继续循环,直到找到合适的iii为止
4.求所有原根
- 枚举φ(m)\varphi(m)φ(m)以内的正整数sss
- 如果sss与φ(m)\varphi(m)φ(m)互质,则asa^sas是一个原根(阶的性质4)
洛谷P6091(求模m意义下的原根)
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define Buff std::ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
#define lowbit(x) (x & (-x))
#define ls (rt * 2)
#define rs (rt * 2 + 1)
typedef long long ll;
const ll mod = 1000000007;
const ll MAXN = 1e7 + 10;
const double eps = 1e-8;
//======================================
vector<ll> primes;
bitset<MAXN> st, exist;
ll euler[MAXN];
//求最小公约数
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
//快速幂
ll qpow(ll a, ll k, ll p) {
ll res = 1;
while (k) {
if (k & 1) res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}
//把1~n当中的素数筛选出来,同时把1~n的欧拉函数值求出来
void get_eulers(ll n) {
euler[1] = 1;
for (ll i = 2; i <= n; i++) {
if (!st[i]) primes.push_back(i), euler[i] = i - 1;
for (ll j = 0; primes[j] <= n / i; j++) {
st[i * primes[j]] = 1;
if (i % primes[j] == 0) {
euler[i * primes[j]] = euler[i] * primes[j];
break;
}
euler[i * primes[j]] = euler[i] * (primes[j] - 1);
}
}
}
//标记是否存在原根
void init() {
exist[1] = exist[2] = exist[4] = 1;
for (auto x : primes) {
if (x % 2) {
for (ll i = x; i < MAXN; i *= x) {
exist[i] = 1;
if (i * 2 < MAXN) exist[i * 2] = 1;
}
}
}
}
//分解质因数
vector<ll> get_primesfactor(ll x) {
vector<ll> res;
// for (ll i = 2; i <= x / i; i++)
// if (x % i == 0) {
// res.push_back(i);
// while (x % i == 0) x /= i;
// }
// if (x > 1) res.push_back(x);
for (auto prime : primes) {
if (prime > x) break;
if (x % prime == 0) res.push_back(prime);
}
return res;
}
//求解质因数
vector<ll> get_primative_roots(ll m) {
vector<ll> v;
//第二步
if (!exist[m]) return v;
ll phi = euler[m], fst;
//第三步的第一小步
auto factors = get_primesfactor(phi);
//第三步的第二小步
for (ll i = 1;; i++) {
if (gcd(i, m) != 1) continue;
bool ok = true;
//第三步的第三小步
for (auto x : factors) {
if (qpow(i, phi / x, m) == 1) {
ok = false;
break;
}
}
if (ok) {
fst = i;
break;
}
}
//第四步
ll cur = fst;
for (ll i = 1; i <= phi; i++) {
if (gcd(phi, i) == 1) v.push_back(cur);
cur = cur * fst % m;
}
return v;
}
// int get_minimum_primitive_root(int m) {
// if (!exist[m]) return 0;
// int phi = euler[m];
// for (int i = 1;; i++) {
// if (gcd(i, m) != 1) continue;
// auto factors = get_primesfactor(phi);
// bool ok = true;
// for (auto x : factors)
// if (qpow(i, phi / x, m) == 1) {
// ok = false;
// break;
// }
// if (ok) return i;
// }
// }
int main() {
Buff;
// clock_t c1 = clock();
// #ifdef LOCAL
// freopen("in.in", "r", stdin);
// freopen("out.out", "w", stdout);
// #endif
//=========================================
ll t;
ll n = 1000000;
//第一步的第一小步
get_eulers(n);
//第一步的第二小步
init();
cin >> t;
while (t--) {
ll n, d, m, s, t, x, id, j;
cin >> n >> d;
auto ans = get_primative_roots(n);
ll len = ans.size();
sort(ans.begin(), ans.end());
cout << len << endl;
for (int i = d; i <= len; i += d) {
cout << ans[i - 1] << " ";
}
cout << endl;
}
//=========================================
// cerr << "Time Used:" << clock() - c1 << "ms" << endl;
}
本文深入探讨了模数计算中的欧拉定理和原根概念。原根是指模数下满足特定条件的元素,其阶是对应循环节的最短长度。文章详细阐述了原根的性质、判定定理、存在性和计算方法,为理解模数运算提供了关键理论支持。
&spm=1001.2101.3001.5002&articleId=119885337&d=1&t=3&u=46df35b36c244a6e9fba49d0c00a3af4)
4346

被折叠的 条评论
为什么被折叠?



