如何在复数域或模素数域下找单位根
如何在复数域或模素数域下找单位根
参考文章:CF1103E Radix sum - 洛谷专栏、数学小记 #3:从 CF1103E 浅谈异或卷积 - 洛谷专栏。
复数域
可以使用 polar(1, 2 * pi / m) 获得复数域下的 \(m\) 次本原单位根。需要慎重使用这样的单位根。
模素数域(素数自选)
如果有素数 \(p\) 和正整数 \(m\) 满足 \(m|(p-1)\),则可以在 \(\mathbb F_p\) 下找到 \(m\) 次本原单位根(即原根的 \((p-1)/m\) 次方)。
洛谷原根模板题太恶臭了,在这里放一下求原根的代码:
// mint 是 F_p 下的数,代码求出 p 的最小原根
mint pmroot() {
vector<int> pri;
int m = mint::mod - 1;
for (int i = 2; i * i <= m; i++) if (m % i == 0) {
pri.push_back(i);
while (m % i == 0) m /= i;
}
if (m > 1) pri.push_back(m);
m = mint::mod - 1;
for (mint g = 1; ; g += 1) {
bool flag = false;
for (int p : pri) {
if (qpow(g, m / p) == 1) flag = true;
}
if (!flag) return g;
}
throw -1;
}
模素数域
若 \(m\) 极小,则可以扩域维护每个数为 \(f_0+f_1w+f_2w^2+\cdots+f_{m-1}w^{m-1}\) 的形式,最后将这个多项式模 \(m\) 级分圆多项式 \(\Phi_m(w)\) 获得真实值。
分圆多项式
\(m\) 级分圆多项式 \(\Phi_m(x)\) 是一个在 \(\mathbb Z[x]\) 上 \(\varphi(m)\) 次的不可约首一多项式,满足
\[\Phi_n(x)=(x-w_1)(x-w_2)\cdots(x-w_{\varphi(n)})=\prod_{i=0}^{n-1}(x-w^i)^{[\gcd(i, n)=1]}
\]
其中 \(w_1, w_2, \cdots, w_{\varphi(n)}\) 是全部 \(n\) 次本原单位根,\(w\) 在 \(w_1, w_2, \cdots, w_{\varphi(n)}\) 中任取。根据一些资料可以得知:
\[\prod_{d|n}\Phi_d(x)=x^n-1
\]
\[\Phi_n(x)=(-1)^{[n=1]}\prod_{d|n}(1-x^d)^{\mu(n/d)}
\]
void init() { // k 次分圆多项式,次数为 phi[k]
T[0] = 1;
for (auto i : d[k]) { // d[k] 是 k 的所有因子
if (mu[k / i] == 1)
for (int j = phi[k]; j >= i; j--) T[j] -= T[j - i];
else if (mu[k / i] == -1)
for (int j = i; j <= phi[k]; j++) T[j] += T[j - i]; // 实际上是退背包
}
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18737658
浙公网安备 33010602011771号