题解:LG1520 因式分解
分圆多项式太毒瘤了!qwq
先尝试几个小的 \(n\):
发现右边的项数刚好等于 \(n\) 的约数个数。
又由于 \(x^n-1\) 的根就是全体 \(n\) 次单位根:
因此现在要做的是:将每个 \(n\) 次单位根分配给 \(n\) 的每个因子 \(d\),一个方法是将 \(\omega_{n}^i\) 分配给 \(\gcd(n,i)\),那么有:
把第二个连乘里的东西记作 \(\phi_{n/d}(x)\),那么有:
上面的 \(\phi\) 便是我们称之为分圆多项式的东西,这个看似从天而降的想法其实有很简单的动机。
需要证明两个东西:\(\phi_n(x)\) 是整系数多项式,并且不可分解成两个次数更小的整系数多项式的乘积(不可约多项式)。
数学归纳法,假设已证得 \(\forall m<n,\phi_m(x)\) 均为整系数多项式,由于:
由高斯引理得 \(\prod_{d|n,d<n}\phi_d(x)\) 为本原多项式,故 \(\phi_n(x)\) 为整系数多项式。
然后证 \(\phi_n(x)\) 是不可约多项式。
反证,设 \(\phi_n(x)=f(x)g(x)\),其中 \(f,g\) 均是首一多项式,且 \(f(x)\not=1\) 且不可约。证明思路是得出 \(\phi_n\) 的所有根均为 \(f\) 的根,进而有 \(\phi_n(x)=f(x)\)。
设 \(z\) 是 \(f(x)\) 的一个根,\(p\) 是一个与 \(n\) 互素的素数,那么 \(z^p\) 是 \(\phi_n(x)\) 的根,即是 \(f(x)\) 或 \(g(x)\) 的根。
下面假设 \(z^p\) 是 \(g(x)\) 的根,从而导出矛盾。由假设得 \(z\) 是 \(f(x)\) 和 \(g(x^p)\) 的公共根,从而有 \(f(x)\mid g(x^p)\),设 \(g(x^p)=f(x)h(x)\),那么 \(f(x)h(x)\equiv g(x^p)\equiv g(x)^p\pmod p\)(使用 Lucas 定理)。
设 \(x^n-1=\phi_n(x)r(x)\),那么 \(x^n-1\equiv f(x)g(x)r(x)\pmod p\)。由域上多项式的分解的唯一性,\(f(x)\) 作为模 \(p\) 意义下的多项式,其每个不可约因子 \(u(x)\mid g(x)^p\),因而也有 \(u(x)\mid g(x)\),这说明 \(x^n-1\) 在模 \(p\) 意义下有重因式 \(u(x)\),即 \(x^n-1\equiv0\pmod p\) 有重根,与 \(\gcd(n,p)=1\) 矛盾。
故 \(z^p\) 只能是 \(f(x)\) 的根,由此可得 \(\phi_n\) 的所有根均为 \(f\) 的根,故 \(\phi_n(x)=f(x)\),即 \(\phi_n(x)\) 是不可约多项式。
因此一开始的式子:
的确给出了 \(x^n-1\) 的完全分解。
现在考虑如何计算分圆多项式 \(\phi_n(x)\)。
两边同时取 \(\ln\):
使用莫比乌斯反演:
再 \(\exp\) 回去:
把负号提一个出来:
分 \(\mu(d)\) 的取值讨论:
- 若 \(\mu(d)=0\),对答案不会有影响;
- 若 \(\mu(d)=1\),即乘上 \(1-x^{\frac{n}{d}}\),跑一个 01 背包状的东西即可;
- 若 \(\mu(d)=-1\),即乘上 \(\dfrac{1}{1-x^{\frac nd}}=1+x^{\frac nd}+x^{\frac{2n}{d}}+\dots\),跑一个完全背包即可。
#include <bits/stdc++.h>
using namespace std;
typedef vector<int> vec;
const int N = 5005;
int n, tot, pri[N], mu[N], cnt;
bool vis[N];
vec ans[N];
bool cmp(const vec &a, const vec &b) {
int sa = a.size(), sb = b.size();
if (sa != sb) return sa < sb;
for (int i = sa - 1; ~i; i--) {
if (abs(a[i]) != abs(b[i])) return abs(a[i]) < abs(b[i]);
else if ((a[i] < 0) ^ (b[i] < 0)) return a[i] < 0;
}
return 0;
}
void sieve(int n) {
mu[1] = 1;
for (int i = 2, k; i <= n; i++) {
if (!vis[i]) pri[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && (k = i * pri[j]) <= n; j++) {
vis[k] = 1;
if (!(i % pri[j])) break;
mu[k] = -mu[i];
}
}
}
vec calc(int n) {
vec a, b, c; c.resize(n + 1), c[0] = 1;
for (int i = 1; i * i <= n; i++) {
if (n % i) continue;
if (mu[n / i] == 1) a.push_back(i);
else if (mu[n / i] == -1) b.push_back(i);
if (i * i == n) continue;
if (mu[i] == 1) a.push_back(n / i);
else if (mu[i] == -1) b.push_back(n / i);
}
for (int x : a) for (int i = n; i >= x; i--) c[i] -= c[i - x];
for (int x : b) for (int i = x; i <= n; i++) c[i] += c[i - x];
if (n == 1) for (int &x : c) x = -x;
while (!c.back()) c.pop_back();
return c;
}
void print(const vec &a) {
int s = a.size() - 1;
for (int i = s; ~i; i--) {
// cerr << a[i] << ' ';
if (a[i] == 0) continue;
if (a[i] == 1) {
if (i != s) putchar('+');
if (i == 0) putchar('1');
} else if (a[i] == -1) {
putchar('-');
if (i == 0) putchar('1');
} else if (a[i] > 0) {
if (i == s) printf("%d", a[i]);
else printf("+%d", a[i]);
} else printf("%d", a[i]);
if (i != 0) {
if (i > 1) printf("x^%d", i);
else putchar('x');
}
}
}
int main() {
scanf("%d", &n), sieve(n);
if (n == 1) return puts("x-1"), 0;
for (int i = 1; i * i <= n; i++) {
if (n % i) continue;
ans[++cnt] = calc(i);
if (i * i != n) ans[++cnt] = calc(n / i);
}
sort(ans + 1, ans + 1 + cnt, cmp);
for (int i = 1; i <= cnt; i++) putchar('('), print(ans[i]), putchar(')');
}
浙公网安备 33010602011771号