【学习笔记】原根与指标
程序员文章站
2022-05-09 13:14:43
...
1. 阶
1.1 定义
- 设正整数 , 是满足 ( 与 互质)的整数,则必有一个正整数 ,使得 。
- 满足条件的最小的正整数 ,称为 模 的阶,记作 。
- 注意,若 ,则不存在 模 的阶。
1.2 阶的性质
- 设 ,。
- 设 ,。
2. 原根
2.1 定义
- 设正整数 , 是满足 的整数,若 ,则称 为模 的一个原根。
2.2 解性
- 设正整数 , 的原根是一些关于 的剩余类(原根可以不止一个)。
- 所以研究原根时,我们只需要研究 范围内的解即可。
2.3 原根的性质
- 只有 有原根。
- 一个数 若存在原根,则它有 个原根。
- 记 ,则 模 两两不同余,当 是 的原根时, 构成模 的简化剩余系。特别地,当 是质数时, 对 取模后对应为 。
2.4 求一个数原根的方法
- 我们已知一个数 存在原根。
- 我们现在要找到 最小的原根。
- 假设我们现在枚举到一个 ,并且 ,要验证 是否是 的原根。
- 根据 ,我们只需要验证对于每个 ,是否均满足 。
- 我们设 ( 是质数)。
- 因为若 ,则 ,所以我们只需要验证,对于每个 ,均满足 即可。
- 只需要暴力枚举验证即可。
- 最小原根的范围都很小。
//mod是指需要求mod的最小原根,phi是mod的phi函数值
inline int find_root(const int &mod, const int &phi)
{
static int p[MaxCnt];
static int cnt;
cnt = 0;
int x = phi;
for (int i = 2; i * i <= phi; ++i)
if (x % i == 0)
{
p[++cnt] = i;
while (x % i == 0)
x /= i;
}
if (x > 1)
p[++cnt] = x;
for (int g = 1; g <= mod; ++g)
{
if (std::__gcd(g, mod) > 1) continue;
bool flg = true;
for (int i = 1; i <= cnt; ++i)
if (qpow(g, phi / p[i], mod) == 1)
{
flg = false;
break;
}
if (flg)
return g;
}
return -1;
}
3. 指标
3.1 定义
- 设 是 的一个原根,整数 ,则在模 意义下有唯一的整数 ,使得 ,则称 为以 为底对模 的一个指标,记作 。
3.2 指标的性质
3.3 求指标的方法
- 求指标的运算也叫做离散对数。
- 求指标即求 的最小自然数解。
- 使用 算法即可。
4. N次剩余问题
- 问题:求解 在模 意义下的所有解, 是质数。
- 首先我们知道,当 时,方程只有 一个解。
- 否则 。
- 我们先找到 的最小原根 。
- 因为 是质数且 ,所以每个 ,我们都能找到 和 。
- 那么原方程等价于 。
- 那么我们只需要用 解这个简单的同余方程即可。
- 当 时,原方程无解。
- 否则我们求出最小自然数解 ,然后将在 内的 的 记录下来。
- 然后所有的 即为答案。
- 代码:(BZOJ1319)
#include <bits/stdc++.h>
int p, K, a, g, t;
int anscnt, ans[1000010];
inline int qpow(int a, int b, const int &p)
{
int res = 1;
for (; b; b >>= 1, a = 1LL * a * a % p)
if (b & 1)
res = 1LL * res * a % p;
return res;
}
inline int find_root(const int &p)
{
int n = p - 1, x = p - 1;
static int div[1000010], cnt;
cnt = 0;
for (int i = 2; i * i <= n; ++i)
if (x % i == 0)
{
div[++cnt] = i;
while (x % i == 0)
x /= i;
}
if (x > 1)
div[++cnt] = x;
for (int g = 1; g <= p; ++g)
{
bool flg = true;
for (int i = 1; i <= cnt; ++i)
if (qpow(g, (p - 1) / div[i], p) == 1)
{
flg = false;
break;
}
if (flg)
return g;
}
return -1;
}
inline int solve_BSGS(const int &a, const int &b, const int &p)
{
std::map<int, int> ha;
ha.clear();
int t = ceil(sqrt(p)), x = 1;
for (int i = 1; i <= t; ++i)
{
x = 1LL * x * a % p;
ha[1LL * x * b % p] = i;
}
int y = x;
for (int i = 1; i <= t; ++i)
{
if (ha.find(y) != ha.end())
return i * t - ha[y];
y = 1LL * y * x % p;
}
return -1;
}
inline int exgcd(const int &a, const int &b, int &x, int &y)
{
if (!b)
return x = 1, y = 0, a;
int res = exgcd(b, a % b, y, x);
y -= a / b * x;
return res;
}
int main()
{
scanf("%d%d%d", &p, &K, &a);
if (a == 0)
return puts("1\n0"), 0;
g = find_root(p);
t = solve_BSGS(g, a, p);
int x, y;
int d = exgcd(p - 1, K, x, y);
if (t % d)
return puts("0"), 0;
int mod = (p - 1) / d;
y = (1LL * y * (t / d) % mod + mod) % mod;
for (; y < p; y += mod)
ans[++anscnt] = qpow(g, y, p);
std::sort(ans + 1, ans + anscnt + 1);
printf("%d\n", anscnt);
for (int i = 1; i <= anscnt; ++i)
printf("%d\n", ans[i]);
return 0;
}
上一篇: WEB学习——Mysql&JDBC
下一篇: MySQL多表&JDBC