1 条题解
-
0
自动搬运
来自洛谷,原作者为

NaCly_Fish
北海虽赊,扶摇可接。搬运于
2025-08-24 21:26:01,当前版本为作者最后更新于2020-03-01 13:05:09,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
已重制,尽可能兼顾浅显易懂与严谨性地说明这题。
思路
我们要对 进行因式分解,而我们知道的是 有 个复根,称为单位根,分别记为 。
也就是说:
如果能对这 个根进行分组,使得每一组构成的多项式都是整系数的,且不可约,那么我们就完成了此问题。
分圆多项式
方便后面表述,这里定义:对于复数 ,若 ,且对于任意整数 都有 ,就称 为 次本原单位根。
定义分圆多项式 为
$$\phi_n(x)=\prod_{k=0}^{n-1}(x-\omega_n^k)^{[\gcd(n,k)=1]} $$(即它是由所有 次本原单位根构成的首项为 的多项式)
对于任意 次单位根 ,都存在唯一的 ,使得 是 次本原单位根。这是因为若 ,取 ,那么 , 是 次本原单位根。
使用这种方法来分配 次单位根, 可以表示为分圆多项式的乘积:
然后你可能会问, 怎么算?
将等式两边取对数,得
看到这个形式想到什么?没错,就是 mobius 反演。
$$\ln\phi_n(x)=\sum_{d|n}\ln(x^d-1)\mu\left(\frac nd \right) $$再 回去,结果就出来了
$$\phi_n(x)=\prod_{d|n}(x^d-1)^{\mu\left(\frac nd \right)} \quad \texttt{(2)} $$如果想了解相关证明,还请继续往下阅读。
整系数的证明
先来证明个简单的: 是整系数多项式。
不妨考虑将 式中的乘积分组,将 的部分记为 ,将 的记为 。
显然 和 都是首项为 的整系数多项式,且 是一个有理系数的多项式。再加上 的首项系数为 ,使用 多项式除法 的计算过程中必然都是整数,所以 是整系数多项式。
引入:最小多项式
证明 在有理数域上的不可约性比较麻烦。我们要引入一个重要概念:最小多项式。
对于一个代数数 ,能满足 的、非常数的、首项为 且次数最低的多项式称为「最小多项式」。
最小多项式有三大性质:「不可约性」、「唯一性」,以及任意以 为根的多项式都能被 整除。具体证明见 wiki 上的页面。
不可约性的证明
现在让我们开始吧!
考虑反证法,假设 在有理数域上可约。那么存在一个最高次项系数为 的、非常数的、整系数不可约多项式 为 的因式。现在就可以将其写为 。
然后选取 和 分别为 和 的根(显然它们也都是 次本原单位根)。不过我们的选取有条件,要使得 中的 最小。
值得说明的是:固定 与 时,这样的 唯一存在。因为设 ,( 均与 互质),那么 在 以内有唯一解。找出 的最小质因子 ,那么有 ,所以 也是 次本原单位根。根据分解的结果, 要么是 的根,要么是 的根。
如果 ,那么 ,这说明我们选取的这组 没能使得 最小,与假设矛盾;
所以只能是 。再根据假设, 已经取到最小了,那就只能有 ,即最小的 必然是个质数。进一步地,根据 的不可约性与 ,可知 是 中 的最小多项式。由于 ,所以 能整除 (使用引理)。
现在我们将问题转移到有限域 中。
$$h(x)^p\equiv \sum_{i=0}^p\binom pi \left( \frac{h(x)-h_0}{x} \right)^{p-i} x^{p-i}h_0^i\equiv h_0^p+x^p\left( \frac{h(x)-h_0}{x} \right)^p \pmod p $$
在 上的多项式 总有 (这是 Lucas 定理):如此展开下去计算即可证明。
然后对于整系数多项式 ,我们记 是其映射到 上的结果。具体地,就是将每一项系数都对 取模。
现在我们知道,。由于 是 的因式, 和 之间必然存在一个公因式 。现在也就是说, 里面有重复的因式 ,对于 也会有重因式()。
最后,我们发现 (因为 )。按理说若 有重因式, 与 就会有公因式 —— 但现在看来这不可能,因为 没有 作为根而 只有 是根。这样就导出了矛盾。
即, 在有理数域上是不可约的。
计算细节
最后是一些计算上的细节,求 时,需要进行 次多项式运算,每次都是 乘/除 一个形如 的多项式,保留到 次系数即可。即求 的时间复杂度为 ,应该没什么特别好的办法优化。
参考代码
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define N 10003 #define ll long long #define p 998244353 using namespace std; int mu[N],pr[N>>1]; bool vis[N]; struct poly{ int a[N]; int t; inline poly(int t=0):t(t){ memset(a,0,sizeof(a)); } inline int operator [] (const int& x) const{ return a[x]; } inline int& operator [] (const int& x){ return a[x]; } inline bool operator < (const poly& b) const{ if(t!=b.t) return t < b.t; for(int i=t;~i;--i){ if(abs(a[i])!=abs(b[i])) return abs(a[i])<abs(b[i]); if(a[i]!=b[i]) return a[i]<b[i]; } return true; } inline void print(){ if(abs(a[t])!=1) printf("%dx^%d",a[t],t); else{ if(t==1) putchar('x'); else printf("x^%d",t); } for(int i=t-1;i;--i){ if(a[i]==0) continue; if(a[i]>0) putchar('+'); else putchar('-'); if(abs(a[i])!=1) printf("%dx",abs(a[i])); else putchar('x'); if(i!=1) printf("^%d",i); } printf(a[0]>0?"+1":"-1"); } }phi[73]; void sieve(int n){ int cnt = 0; mu[1] = 1; for(int i=2;i<=n;++i){ if(!vis[i]){ pr[++cnt] = i; mu[i] = -1; } for(int j=1;j<=cnt&&i*pr[j]<=n;++j){ vis[i*pr[j]] = true; if(i%pr[j]==0){ mu[i*pr[j]] = 0; break; } mu[i*pr[j]] = -mu[i]; } } } inline void multiply(poly &f,int d){ f.t += d; for(int i=f.t;i>=d;--i) f[i] = f[i-d]-f[i]; for(int i=0;i!=d;++i) f[i] = -f[i]; } inline poly getphi(int n){ static poly mul,div,res; mul = div = poly(); mul[0] = div[0] = 1; for(int d=1;d*d<=n;++d){ if(n%d!=0) continue; if(mu[n/d]==1) multiply(mul,d); else if(mu[n/d]==-1) multiply(div,d); if(d*d==n) continue; if(mu[d]==1) multiply(mul,n/d); else if(mu[d]==-1) multiply(div,n/d); } if(div.t==0) return mul; res.t = mul.t-div.t; res[0] = mul[0]*div[0]; for(int i=1;i<=res.t;++i){ res[i] = mul[i]; for(int j=0;j!=i;++j) res[i] -= res[j]*div[i-j]; res[i] *= div[0]; } return res; } int n,fc; int main(){ scanf("%d",&n); sieve(n); for(int i=1;i*i<=n;++i){ if(n%i!=0) continue; phi[++fc] = getphi(i); if(i*i!=n) phi[++fc] = getphi(n/i); } if(fc==1){ phi[1].print(); return 0; } sort(phi+1,phi+1+fc); for(int i=1;i<=fc;++i){ putchar('('); phi[i].print(); putchar(')'); } return 0; }
- 1
信息
- ID
- 513
- 时间
- 800ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者