不那么详细的多项式笔记

news/2025/11/24 22:35:21/文章来源:https://www.cnblogs.com/biyimouse/p/19266095

单位根

其实我们应该先学复数,但我觉得复数学过高中数学的应该都会。

\(z = a\cos \theta + a\sin \theta \mathrm{i} = (a, \theta)\),其中 \(a\) 为复数模长,\(\theta\) 为辐角。根据欧拉公式 \(e^{i\theta} = \cos \theta + \mathrm{i}\sin \theta\),所以 \(z = ae^{i\theta}\)

所以两个复数相乘就是模长相乘,辐角相加。

推论: \((\cos \theta + \mathrm{i} \sin \theta)^n = \cos(n\theta) + \mathrm{i}\sin(n \theta)\),根据欧拉公式简单即可证明。

定义 \(n\)单位根\(z^n = 1\) 的解,这个方程显然要有 \(n\) 个解,不妨设 \(\omega_n^k\) 表示第 \(k\) 个解。

对于 \(z^n = 1\) 两边同时取模得到 \(|z^n| = 1\),于是 \(|z|^n = 1\),我们得到 \(|z| = 1\)。所以单位根位于原点为圆心半径为 \(1\) 的圆上。

所以我们设 \(\omega_n^k = \cos \theta + \mathrm{i} \sin \theta\)。于是 \((\omega_n^k)^n = \cos(n\theta) + \mathrm{i}\sin(n \theta) = 1 + 0\mathrm{i}\)

于是有 \(\cos(n\theta) = 1\), \(\sin(n \theta) = 0\)。解得 \(\theta = \frac{2k\pi}{n}\)

此时来研究一下单位根的性质,有:

  • \(\omega_n^k = (\omega_n^1)^k\)
  • \(\omega_n^{k + \frac{n}{2}} = -\omega_n^k\)\(n\) 为偶数),诱导公式即可证明,更进一步 \(\omega_n^k = \omega_n^{k \bmod n}\)
  • \(\omega_n^{0 \sim n - 1}\) 互不相同
  • \(\omega_{2n}^{2k} = \omega_n^k\)

FFT

考虑先将多项式补到 \(n = 2^k\) 的形式。我们的目的是求出一个 \(n - 1\) 次多项式在每个 \(n\) 次单位根下的点值。

\(m = \frac{n}{2}\)

\(A(x) = \sum_{i = 0}^{n - 1} a_ix^i = \sum_{i = 0}^{m - 1}a_{2i}x^{2i} + \sum_{i = 0}^{m - 1}a_{2i + 1}x^{2i + 1}\)

\(A_0(x) = \sum_{i = 0}^{m - 1}a_{2i}x^{i}\)\(A_1(x) = \sum_{i = 0}^{m - 1}a_{2i + 1}x^i\),则 \(A(x) = A_0(x^2) + xA_1(x^2)\)

\(k \in [0, m)\),将 \(\omega_n^k\) 带入 \(A\),有

\[A(\omega_n^k) = A_0(\omega_m^k) + \omega_n^kA_1(\omega_m^k) \]

\(\omega_n^{k + m}\) 带入 \(A\),有

\[A(\omega_n^{k + m}) = A_0(\omega_m^k) - \omega_n^kA_1(\omega_m^k) \]

所以我们只需要将 \(A_0\)\(A_1\) 递归求一下即可,复杂度 \(O(n\log n)\)

IDFT

目的是将 FFT 后的点值还原成系数。设 FFT 后的点值为 \(b\),则 \(b_k = \sum_{i = 0}^{n - 1}a_i \times \omega_n^{ik}\)

结论: \(a_k = \frac{1}{n}\sum_{i = 0}^{n - 1}b_i \omega_n^{-ki}\)

证明:

\[\begin{align} \sum_{i = 0}^{n - 1}b_i \omega_n^{-ki} &= \sum_{i = 0}^{n - 1} \sum_{j = 0}^{n - 1} a_j \omega_n^{ij} \omega_n^{-ik} \\ &= \sum_{j = 0}^{n - 1} a_j \sum_{i = 0}^{n - 1} \omega_n^{i(j - k)} \end{align} \]

\(j = k\) 时贡献总和就是 \(n\),当 \(j \not = k\) 时,有

\[\begin{align} \sum_{i = 0}^{n - 1}\omega_n^{i(j - k)} &= \frac{1 - \omega_n^{(n - 1)(j - k)}\omega_n^{j - k}}{1 - \omega_n^{j - k}} \\ &= \frac{1 - (\omega_n^{n(j - k)})}{1 - \omega_n^{j - k}} \\ &= \frac{1 - 1}{1 - \omega_n^{j - k}} \\ &= 0 \end{align} \]

这里解释一下为什么 \(\omega_n^{n(j - k)} = 1\),因为首先 \(\omega_n^0 = 1\),然后由于单位根本质上相当于在单位圆上绕圈,所以是循环的,这里相当于绕了 \(j - k\) 圈。

于是我们发现只有 \(j = k\) 时有贡献,此时 \(na_k = \sum_{i = 0}^{n - 1}b_i\omega_n^{-ki}\),证完了。

那么我们现在的问题其实是计算 \(B(x) = \sum_{i = 0}^{n - 1}b_i \times x^i\)\(\omega_n^{-k}\) 的点值。考虑有 \(\omega_n^{-k} = \omega_n^{-k + n}\),于是我们只需要 FFT 即可。

FFT 优化

直接递归做这个过程常数比较大跑不过取 \(n = 1e6\),考虑将递归改成迭代的形式。

我们会注意到搜索树的最后一层其实是根据二进制翻转后的大小排序的,然后每一层是把下面一层的合并起来。

这样就跑得非常快了。

const int N = 5000010;
const double PI = acos(-1);
int n, m, tax[N];
complex<double> F[N], G[N];void makerev(int N) {int d = N >> 1, tot = 0;tax[tot ++] = 0, tax[tot ++] = d;for (int w = 2; w <= N; w <<= 1) {d >>= 1; for (int i = 0; i < w; i ++) tax[tot ++] = tax[i] | d;}
}void FFT(complex<double> *A, int N) {for (int i = 1; i < N; i ++) if (tax[i] > i) swap(A[tax[i]], A[i]);for (int len = 2, M = 1; len <= N; M = len, len <<= 1) {complex<double> W(cos(PI / M), sin(PI / M)), w(1.0, 0.0);for (int L = 0, R = len - 1; R < N; L += len, R += len) {auto w0 = w;for (int p = L; p < L + M; p ++) {auto x = A[p] + w0 * A[p + M], y = A[p] - w0 * A[p + M];A[p] = x, A[p + M] = y;w0 *= W;}}}
}int main() {n = read(), m = read();for (int i = 0; i <= n; i ++) F[i] = read();for (int i = 0; i <= m; i ++) G[i] = read();int k = 1;while (k <= n + m) k <<= 1;makerev(k); FFT(F, k); FFT(G, k);for (int i = 0; i < k; i ++) F[i] *= G[i];FFT(F, k); reverse(F + 1, F + k);for (int i = 0; i <= n + m; i ++) printf("%d ", (int)(F[i].real() / k + 0.5));puts("");return 0;
}       

NTT

FFT 存在精度问题,而大部分的计数题都是在模意义下完成的,所以要使用 NTT。

考虑原根,不懂的看这篇。阶与原根 - はなこくん - 博客园

对于素数 \(p\),及其原根 \(g\),我们有 \(g^k\) 的阶数为 \(\frac{p - 1}{\gcd(k, p - 1)}\)。这个阶数显然仍然是 \(p - 1\) 的约数。

证明:

\(n = p - 1\)\(d = \gcd(k, n)\)\(g^k\) 的阶数为 \(r\),则 \(g^{kr} \equiv 1 \pmod p\)。显然 \(n | kr\)

\(k = dk_1, n = dn_1\),转化成 \(n_1 | k_1r\)。由于 \(\gcd(k_1, n_1) = 1\),所以 \(n_1 | r\),因此 \(r\) 最小取到 \(n_1\)

经检验 \(r\)\(n_1\) 可行所以 \(r = \frac{n}{\gcd(k, n)}\)

这同样说明了如果 \(n \not \mid p - 1\),那么不存在阶恰为 \(n\) 的数。否则 \(g^{\frac{p - 1}{n}}\) 的阶显然为 \(n\)。满足单位根性质的前三条。

我们又有 \((g^{\frac{p - 1}{2n}})^2 = g^{\frac{p - 1}{n}}\),即 \((\omega_{2n})^2 = \omega_n\)

由于我们需要 \(n | p - 1\),且 FFT 中的 \(n\) 为二的次幂,于是我们需要一个形如 \(q2^k + 1\)\(p\) 作为模数。

// 洛谷模板题
const int N = 5000010, Mod = 998244353, G = 3;
int n, m, tax[N];
LL f[N], g[N];IL int qmi(int a, int b = Mod - 2, int p = Mod) {int res = 1;while (b) {if (b & 1) res = 1ll * res * a % p;b >>= 1; a = 1ll * a * a % p;}return res;
}const int invG = qmi(G);void makerev(int N) {int d = N >> 1, tot = 0;tax[tot ++] = 0, tax[tot ++] = d;for (int w = 2; w <= N; w <<= 1) {d >>= 1; for (int i = 0; i < w; i ++) tax[tot ++] = tax[i] | d;}
}void FFT(LL A[], int N, int op) {for (int i = 1; i < N; i ++) if (tax[i] > i) swap(A[tax[i]], A[i]);for (int len = 2, M = 1; len <= N; M = len, len <<= 1) {int W = qmi(op ? G : invG, (Mod - 1) / len);for (int L = 0, R = len - 1; R < N; L += len, R += len) {LL w0 = 1;for (int p = L; p < L + M; p ++) {int x = (A[p] + w0 * A[p + M]) % Mod, y = (A[p] + Mod - w0 * A[p + M] % Mod) % Mod;A[p] = x, A[p + M] = y;w0 = w0 * W % Mod;}}}
}int main() {n = read(), m = read();for (int i = 0; i <= n; i ++) f[i] = read();for (int i = 0; i <= m; i ++) g[i] = read();int k = 1;while (k <= n + m) k <<= 1;makerev(k); FFT(f, k, 1); FFT(g, k, 1);for (int i = 0; i < k; i ++) f[i] *= g[i];FFT(f, k, 0);int invk = qmi(k);for (int i = 0; i <= n + m; i ++) printf("%lld ", f[i] * invk % Mod);puts("");return 0;
}       

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/975373.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java的线程池了解吗?

线程池介绍 什么是线程池 线程池是一种池化技术,用户预先创建并管理一组线程,避免频繁创建和销毁线程的开销,提高性能和响应速度 使用线程池的原因降低系统资源消耗:复用线程,不用重复创建,消耗资源 提升系统响应…

超简单!3步生成10W+爆款说唱视频!

不用花钱,不用技术,小白也能轻松搞定大家好,我是磊哥!今天给大家分享一个超级实用的干货——如何免费制作AI说唱视频! 先来看看效果: https://www.bilibili.com/video/BV1JVUCBVEsL/ 是不是很有意思?而且这一切…

深度解析2026美国研究生申请机构:从GPA到藤校,这些机构藏着关键方案

深度解析2026美国研究生申请机构:从GPA到藤校,这些机构藏着关键方案美国研究生申请向来以高竞争、多环节、政策多变著称,顶尖院校热门专业录取率常低于5%,标化成绩、科研实习、文书打磨等任一环节的疏漏都可能错失…

实用指南:介绍一下Ribbon

实用指南:介绍一下Ribbon2025-11-24 22:27 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; f…

P27_完整的模型训练套路(二)

P27_完整的模型训练套路(二)如何辨别模型在训练过程中有没有训练好以及有没有达到我需要训练的需求? 不需要对模型进行调优了,直接利用现有的模型来进行一个测试: 9.测试步骤开始: 用with torch.no_grad():环境取…

洛谷 P1496:火烧赤壁 ← 离散化(数组 + sort + STL map)

​【题目来源】https://www.luogu.com.cn/problem/P1496【题目描述】曹操平定北方以后,公元 208 年,率领大军南下,进攻刘表。他的人马还没有到荆州,刘表已经病死。他的儿子刘琮听到曹军声势浩大,吓破了胆,先派人…

P28_完整的模型训练套路(三)

P28_完整的模型训练套路(三)本节进行训练细节总结 打开官网:torch.nn.Module,可以查看train mode 和eval mode .train()和.eval()只对特定层如Dropout和BatchNorm层起作用,但是最好还是加上; 即在训练开始前加上…

奶酪和机器人 非标准化的步数遍历

当有不超过几步的时候 我们的遍历是:遍历带点所有可达状态 1.奶酪 垂直水平的遍历 也可以用第二种 for(int i=0;i<4;i++){for(int step=1;step<=k;step++){int nx=x+dx[i]*step;int ny=y+dy[i]*step;int nw=sw+…

6个适合做 PoC 的开源无代码/低代码工具推荐

汇总了 6 个适合快速构建 PoC 的开源低代码/无代码工具,为你提供在不同验证场景下的选择指南。原文链接:https://www.nocobase.com/cn/blog/6-open-source-no-low-code-tools-for-building-poc 如果在几年前你问一位…

2025年度木门厂商推荐榜单与选择指南:一份基于行业专业数据的权威分析报告,整木/实木/原木门十大主流供应商解析

在家居装修中,一扇好门不仅是空间的分隔,更是安全、静音与美学的集合体。在2025年,随着消费升级和健康家居理念深入人心,人们对木门的材质、工艺、环保标准乃至智能化程度都提出了更高要求。如何在众多品牌中精准锁…

C# Quartz 定损执行 - microsoft

在 C# 中,如果你想要使用 Quartz.NET 库来安排一个任务每小时执行一次,你可以使用 StdSchedulerFactory 类来创建一个调度器(Scheduler),并配置一个 Cron 触发器(CronTrigger)。 步骤 1: 安装 Quartz.NETInstal…

2025美国本科申请中介深度解析:适配不同背景的梦校推手,谁能助你敲开美国名校门?

2025美国本科申请中介深度解析:适配不同背景的梦校推手,谁能助你敲开美国名校门?美国本科申请以其复杂的网申系统、多元的评估维度及多变的招生政策,成为留学申请中的“硬骨头”。专业的申请中介能凭借对院校偏好的…

Rokid AI眼镜开发 —— 戴上Rokid Glasses的你有多强

我们team——看看你有多强队在Rokid 杭州赛中做的一款应用是"战斗力识别",这款产品是基于Rokid AI glasses的 产品,其后台是在灵珠平台上搭建的工作流。先说下设计思路和主要规则: 主要分四大块功能 :1.眼…

机器人的记忆化搜索

dp[][]从这个点为起点的路径数量 终点的自己到自己算一种 使用递推f()=所有出去之和 #include <bits/stdc++.h> using namespace std; int n,m; int g[105][105];int visited[105][105]; int dp[105][105];//从这…

# 数据库对AI向量语义搜索的支持深度分析:PostgreSQL、MySQL、Elasticsearch技术选型指南

# 数据库对AI向量语义搜索的支持深度分析:PostgreSQL、MySQL、Elasticsearch技术选型指南Posted on 2025-11-24 22:19 吾以观复 阅读(0) 评论(0) 收藏 举报关联知识库:# 数据库对AI向量语义搜索的支持深度分析…

# 编程十四年感悟:复杂度管理与工程实践

# 编程十四年感悟:复杂度管理与工程实践Posted on 2025-11-24 22:19 吾以观复 阅读(0) 评论(0) 收藏 举报关联知识库:# 编程十四年感悟:复杂度管理与工程实践编程十四年感悟:复杂度管理与工程实践原文链接:…

Ai元人文:行为化不是放弃概念,而是通往概念的坚实阶梯

Ai元人文:行为化不是放弃概念,而是通往概念的坚实阶梯 主流路径的困境在于,它试图让AI从一个它无法企及的终点(抽象概念)开始学习。这就像让一个婴儿先理解“爱情”的哲学定义,再去学习如何爱。 而“行为化”之路…

基于RS485通讯及Modbus通讯协议的温湿度变送器

基于RS485通讯及Modbus通讯协议的温湿度变送器组成: 1.主控芯片STC12C5A60S2 STC12C5A60S2是增强型8051CPU,1T,单时钟/机器周期,指令代码完全兼容传统8051,指令执行速度是其8-12倍,响应更快。内置1KB的EEPROM(S…

小额支付系统:详细处理逻辑(底层)

小额支付系统:不止看懂还看透,细节里藏精华(附全流程步骤) 想了好久,决定还是写一下​小额批量支付系统​,尽管这块内容在各个平台被许多大佬普及了很多次了,或许你已经看腻了,或许你也了然于胸了,但是我觉得…

“大概率上涨”的推荐

基于提供的CSV文件数据,我整合并筛选了“大概率上涨”的推荐股票列表。筛选标准侧重于模型预测的一致性和出现频率(即上涨比例),同时考虑平均上涨概率和测试准确率。从数据中,我发现两只股票(sz.000798 和 sh.60…