• 预备知识:FFT/NTT

  • 多项式的逆

    给定一个多项式 F(x)F(x)F(x),请求出一个多项式 G(x)G(x)G(x),满足 F(x)∗G(x)≡1(mod xn)F(x)*G(x) \equiv 1(mod\ x^n)F(x)∗G(x)≡1(mod xn)。

    系数对 998244353998244353998244353 取模,1≤n≤1051≤n≤10^51≤n≤105

    首先将多项式的长度拓展至222的次幂,然后我们要求的是

    G(x)∗F(x)≡1 (mod xn)G(x)*F(x) \equiv 1\ (mod\ x^n)G(x)∗F(x)≡1 (mod xn)假设已经求出了

    H(x)∗F(x)≡1 (mod x⌈n2⌉)H(x)*F(x) \equiv 1\ (mod\ x^{⌈\frac n2⌉})H(x)∗F(x)≡1 (mod x⌈2n​⌉)又因为有

    G(x)∗F(x)≡1 (mod x⌈n2⌉)G(x)*F(x) \equiv 1\ (mod\ x^{⌈\frac n2⌉})G(x)∗F(x)≡1 (mod x⌈2n​⌉)两式相减有

    (G(x)−H(x))∗F(x)≡0 (mod x⌈n2⌉)(G(x)-H(x))*F(x) \equiv 0\ (mod\ x^{⌈\frac n2⌉})(G(x)−H(x))∗F(x)≡0 (mod x⌈2n​⌉)G(x)−H(x)≡0 (mod x⌈n2⌉)G(x)-H(x) \equiv 0\ (mod\ x^{⌈\frac n2⌉})G(x)−H(x)≡0 (mod x⌈2n​⌉)因为左边得到的多项式前⌈n2⌉{⌈\frac n2⌉}⌈2n​⌉项都是000,平方前nnn项都是000,所以有

    (G(x)−H(x))2≡0 (mod xn)(G(x)-H(x))^2 \equiv 0\ (mod\ x^{n})(G(x)−H(x))2≡0 (mod xn)G2(x)−2G(x)H(x)+H2(x)≡0 (mod xn)G^2(x)-2G(x)H(x)+H^2(x)\equiv 0\ (mod\ x^n)G2(x)−2G(x)H(x)+H2(x)≡0 (mod xn)两边同时乘以F(x)F(x)F(x)

    G(x)−2H(x)+H2(x)F(x)≡0 (mod xn)G(x)-2H(x)+H^2(x)F(x)\equiv 0\ (mod\ x^n)G(x)−2H(x)+H2(x)F(x)≡0 (mod xn)G(x)≡2H(x)−H2(x)F(x) (mod xn)G(x)\equiv2H(x)-H^2(x)F(x)\ (mod\ x^n)G(x)≡2H(x)−H2(x)F(x) (mod xn)

    我们就得到了递推式,时间复杂度如下T(n)=T(n/2)+O(nlog2n)=O(nlog2n)T(n)=T(n/2)+O(nlog_2n)=O(nlog_2n)T(n)=T(n/2)+O(nlog2​n)=O(nlog2​n)

  • 多项式开根

    给定一个 n−1n−1n−1 次多项式 F(x)F(x)F(x),求一个在 mod xnmod\ x^nmod xn 意义下的多项式 G(x)G(x)G(x),使得 G2(x)≡F(x) (mod xn)G^2(x) \equiv F(x) \ (mod\ x^n)G2(x)≡F(x) (mod xn)(多项式的系数在 mod 998244353mod\ 998244353mod 998244353 的意义下进行运算,1≤n≤1051≤n≤10^51≤n≤105)

    同样假设求出了H2(x)≡F(x) (mod x⌈n2⌉)H^2(x)\equiv F(x)\ (mod\ x^{⌈\frac n2⌉})H2(x)≡F(x) (mod x⌈2n​⌉)且有

    G2(x)≡F(x) (mod x⌈n2⌉)G^2(x)\equiv F(x)\ (mod\ x^{⌈\frac n2⌉})G2(x)≡F(x) (mod x⌈2n​⌉)所以

    G(x)−H(x)≡0 (mod x⌈n2⌉)G(x)-H(x) \equiv 0\ (mod\ x^{⌈\frac n2⌉})G(x)−H(x)≡0 (mod x⌈2n​⌉)(G(x)−H(x))2≡0 (mod xn)(G(x)-H(x))^2 \equiv 0\ (mod\ x^{n})(G(x)−H(x))2≡0 (mod xn)G2(x)−2G(x)H(x)+H2(x)≡0 (mod xn)G^2(x)-2G(x)H(x)+H^2(x)\equiv 0\ (mod\ x^n)G2(x)−2G(x)H(x)+H2(x)≡0 (mod xn)F(x)−2G(x)H(x)+H2(x)≡0 (mod xn)F(x)-2G(x)H(x)+H^2(x)\equiv 0\ (mod\ x^n)F(x)−2G(x)H(x)+H2(x)≡0 (mod xn)

    所以2G(x)≡F(x)H(x)+H(x) (mod xn)2G(x)\equiv \frac{F(x)}{H(x)}+H(x)\ (mod\ x^n)2G(x)≡H(x)F(x)​+H(x) (mod xn)

    此处除法转化为乘上多项式的逆,就能递推了,时间复杂度也是O(nlog2n)O(nlog_2n)O(nlog2​n)

  • 多项式求自然对数

    给出 n−1n−1n−1 次多项式 F(x)F(x)F(x),求一个 mod xnmod\ x^nmod xn 下的多项式 G(x)G(x)G(x),满足 G(x)≡ln⁡F(x) (mod xn)G(x) \equiv \ln F(x)\ (mod\ x^n)G(x)≡lnF(x) (mod xn).

    多项式的系数在 mod 998244353mod\ 998244353mod 998244353 的意义下进行运算,1≤n≤1051≤n≤10^51≤n≤105

    G(x)=ln F(x)=∫F′(x)F(x)dx=∫F′(x)F−1(x)dx\begin{aligned}
    G(x)&=ln\ F(x)\\
    &=\int \frac{F'(x)}{F(x)}dx\\
    &=\int F'(x)F^{-1}(x)dx
    \end{aligned}G(x)​=ln F(x)=∫F(x)F′(x)​dx=∫F′(x)F−1(x)dx​所以G=∫F′F−1G=\int F'F^{-1}G=∫F′F−1,直接多项式求逆+多项式求导积分就行了

    求逆复杂度O(nlog2n)O(nlog_2n)O(nlog2​n),求导积分复杂度O(n)O(n)O(n),总时间复杂度仍是O(nlog2n)O(nlog_2n)O(nlog2​n)

  • 多项式exp

    多项式exp是用牛顿迭代做的,我也不会证明牛顿迭代,只会背公式.

    本来牛顿迭代公式是这个样子的xn+1=xn−f(xn)f′(xn)x_{n+1}=x_n-\frac{f(x_n)}{f'(x_n)}xn+1​=xn​−f′(xn​)f(xn​)​

    对于多项式的牛顿迭代长这样un+1=un−f(u,v)fu(u,v)u_{n+1}=u_n-\frac{f(u,v)}{f_u(u,v)}un+1​=un​−fu​(u,v)f(u,v)​

    • 其中f(u,v)f(u,v)f(u,v)表示已知多项式为vvv,未知多项式为uuu的多项式方程,就拿exp为例,原方程为u≡ev (mod xn)u\equiv e^v\ (mod\ x^n)u≡ev (mod xn)两边取对数为ln u≡v (mod xn)ln u−v≡0 (mod xn)\begin{aligned}ln\ u\equiv v\ (mod\ x^n)\\ln\ u-v\equiv 0\ (mod\ x^n)\end{aligned}ln u≡v (mod xn)ln u−v≡0 (mod xn)​那么f(u,v)=ln u−vf(u,v)=ln\ u-vf(u,v)=ln u−v.
    • fu(u,v)f_u(u,v)fu​(u,v)表示的是f(u,v)f(u,v)f(u,v)对uuu取导.注意是对uuu,不是对多项式里的xxx.

      举个栗子,ln vln\ vln v对vvv求导是1v\frac 1vv1​,但是对xxx求导是v′v\frac{v'}{v}vv′​(此处v′v'v′是对xxx求导)

    那么我们就可以推推柿子un+1≡un−(ln un−v(ln un−v)′) (mod xn)≡un−(ln un−v1un) (mod xn)≡un−(ln un−v)un (mod xn)≡un(1−ln un+v) (mod xn)\begin{aligned}u_{n+1}&\equiv u_n-\left(\frac{ln\ u_n-v}{(ln\ u_n-v)'}\right)\ &(mod\ x^n)\\&\equiv u_n-\left(\frac{ln\ u_n-v}{\frac1{u_n}}\right)\ &(mod\ x^n)\\&\equiv u_n-(ln\ u_n-v)u_n\ &(mod\ x^n)\\&\equiv u_n(1-ln\ u_n+v)\ &(mod\ x^n)\end{aligned}un+1​​≡un​−((ln un​−v)′ln un​−v​) ≡un​−(un​1​ln un​−v​) ≡un​−(ln un​−v)un​ ≡un​(1−ln un​+v) ​(mod xn)(mod xn)(mod xn)(mod xn)​然后就套用前面的模板迭代做了

    TIP:TIP:TIP:其实多项式开根也可以用这个方法推出来,有兴趣可以去试试看.

代码
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
namespace READ {
inline void read(int &num) {
char ch; int flg=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flg=-flg;
for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
num*=flg;
}
}
using namespace READ;
const int mod = 998244353, G = 3, inv2 = 499122177;
const int MAXN = 1<<18; // 注意MAXN要大于2*n
int rev[MAXN], Wn[MAXN+1][2], inv[MAXN+1];
inline void reset(int len) { for(int i = 0; i < len; ++i) rev[i] = (rev[i>>1]>>1)|((i&1)?(len>>1):0); }
inline int qmul(int a, int b) {
int res = 1;
while(b) {
if(b&1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod; b>>=1;
}
return res;
}
inline int add(int x, int y) { return x+y>mod ? x+y-mod : x+y; }
namespace Poly {
int A[MAXN],B[MAXN],C[MAXN],D[MAXN],E[MAXN],F[MAXN],GG[MAXN],H[MAXN];//每个不同函数开不同的临时数组,否则可能重复使用
inline void clear(int *b, int n) { for(int i = 0; i < n; ++i) b[i] = 0; } //多清零
inline void NTT(int *arr, int n, int flg) {
int wn, w, A0, wA1, i, j, k;
for(i = 0; i < n; ++i) if(i < rev[i]) swap(arr[i], arr[rev[i]]);
for(i = 2; i <= n; i<<=1) {
wn = Wn[i][(~flg)?0:1];
for(j = 0, w = 1; j < n; j += i, w = 1)
for(k = j; k < j + i/2; ++k, w = 1ll * w * wn % mod) {
A0 = arr[k], wA1 = 1ll * w * arr[k + i/2] % mod;
arr[k] = add(A0, wA1);
arr[k + i/2] = add(A0, -wA1+mod);
}
}
if(!(~flg)) for(i = 0; i < n; ++i) arr[i] = 1ll * arr[i] * inv[n] % mod;
} inline void INV(int *a, int *b, int n) {
clear(b, n<<1), b[0] = qmul(a[0], mod-2);
clear(A, n<<1), clear(B, n<<1);
int len, lim;
for(len = 2; len < (n<<1); len<<=1) {
lim = len<<1;
for(int i = 0; i < len; ++i) A[i] = a[i], B[i] = b[i];
reset(lim); NTT(A, lim, 1); NTT(B, lim, 1);
for(int i = 0; i < lim; ++i) b[i] = ((2ll - 1ll * A[i] * B[i] % mod) * B[i] % mod + mod) % mod;
NTT(b, lim, -1);
for(int i = len; i < lim; ++i) b[i] = 0;
}
for(int i = 0; i < len; ++i) A[i] = B[i] = 0;
for(int i = n; i < len; ++i) b[i] = 0;
} inline void SQRT(int *a, int *b, int n) {
clear(b, n<<1); b[0] = int(sqrt(a[0])+0.5);
int len, lim, *A = GG, *B = H;
clear(A, n<<1), clear(B, n<<1);
for(len = 2; len < (n<<1); len<<=1) {
lim = len<<1;
for(int i = 0; i < len; ++i) A[i] = a[i];
INV(b, B, len);
reset(lim); NTT(A, lim, 1); NTT(B, lim, 1);
for(int i = 0; i < lim; ++i) A[i] = 1ll * A[i] * B[i] % mod;
NTT(A, lim, -1);
for(int i = 0; i < len; ++i) b[i] = 1ll * (b[i] + A[i]) % mod * inv2 % mod;
for(int i = len; i < lim; ++i) b[i] = 0;
}
for(int i = 0; i < len; ++i) A[i] = B[i] = 0;
for(int i = n; i < len; ++i) b[i] = 0;
} inline void INT(int *a, int *b, int n) {
clear(b, n<<1);
for(int i = n-1; i; --i)
b[i] = 1ll * a[i-1] * qmul(i, mod-2) % mod;
b[0] = 0;
} inline void DIF(int *a, int *b, int n) {
clear(b, n<<1);
for(int i = 1; i < n; ++i)
b[i-1] = 1ll * a[i] * i % mod;
b[n-1] = 0;
} inline void LN(int *a, int *b, int n) {
int *A = E, *B = F, len = 1;
clear(A, n<<1), clear(B, n<<1);
INV(a, A, n); DIF(a, B, n);
while(len < (n<<1)) len<<=1;
reset(len); NTT(A, len, 1); NTT(B, len, 1);
for(int i = 0; i < len; ++i) A[i] = 1ll * A[i] * B[i] % mod;
NTT(A, len, -1); INT(A, b, n);
} inline void EXP(int *a, int *b, int n) {
clear(b, n<<1), b[0] = 1;
int len, lim, *A = C, *B = D;
clear(A, n<<1), clear(B, n<<1);
for(len = 2; len < (n<<1); len<<=1) {
lim = len<<1;
LN(b, A, len);
for(int i = 0; i < len; ++i) A[i] = ((i==0)-A[i]+a[i]+mod) % mod, B[i] = b[i];
for(int i = len; i < lim; ++i) A[i] = B[i] = 0;
reset(lim); NTT(A, lim, 1); NTT(B, lim, 1);
for(int i = 0; i < lim; ++i) A[i] = 1ll * A[i] * B[i] % mod;
NTT(A, lim, -1);
for(int i = 0; i < len; ++i) b[i] = A[i];
}
for(int i = n; i < len; ++i) b[i] = 0;
}
}
using namespace Poly;
inline void Pre() { //预处理原根及逆元
for(int i = 1; i <= MAXN; i<<=1)
Wn[i][0] = qmul(G, (mod-1)/i),
Wn[i][1] = qmul(G, (mod-1)-(mod-1)/i),
inv[i] = qmul(i, mod-2);
}
int main () {
Pre();
}

Upd:Upd:Upd:现在看,发现我以前sb了…不用开不同的数组来取地址,直接static定义就行了…

  • 带余除法(待更…)

  • 多项式多点求值(待更…)

多项式的各类计算(多项式的逆/开根/对数/exp/带余除法/多点求值)的更多相关文章

  1. [模板]多项式全家桶小记(求逆,开根,ln,exp)

    前言 这里的全家桶目前只包括了\(ln,exp,sqrt\).还有一些类似于带余数模,快速幂之类用的比较少的有时间再更,\(NTT\)这种前置知识这里不多说. 还有一些基本的导数和微积分内容要了解,建 ...

  2. 洛谷P5282 【模板】快速阶乘算法(多项式多点求值+MTT)

    题面 传送门 前置芝士 \(MTT\),多项式多点求值 题解 这题法老当初好像讲过--而且他还说这种题目如果模数已经给定可以直接分段打表艹过去 以下是题解 我们设 \[F(x)=\prod_{i=0} ...

  3. luogu P5667 拉格朗日插值2 拉格朗日插值 多项式多点求值 NTT

    LINK:P5667 拉格朗日插值2 给出了n个连续的取值的自变量的点值 求 f(m+1),f(m+2),...f(m+n). 如果我们直接把f这个函数给插值出来就变成了了多项式多点求值 这个难度好像 ...

  4. 洛谷P5050 【模板】多项式多点求值

    传送门 人傻常数大.jpg 因为求逆的时候没清零结果调了几个小时-- 前置芝士 多项式除法,多项式求逆 什么?你不会?左转你谷模板区,包教包会 题解 首先我们要知道一个结论\[f(x_0)\equiv ...

  5. 【洛谷P5050】 【模板】多项式多点求值

    code: #include <bits/stdc++.h> #define ll long long #define ull unsigned long long #define set ...

  6. 【BZOJ3625】【CF438E】小朋友和二叉树 NTT 生成函数 多项式开根 多项式求逆

    题目大意 考虑一个含有\(n\)个互异正整数的序列\(c_1,c_2,\ldots ,c_n\).如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合\(\{c_1,c_2,\ldots ,c_n\ ...

  7. 【learning】多项式相关(求逆、开根、除法、取模)

    (首先要%miskcoo,这位dalao写的博客(这里)实在是太强啦qwq大部分多项式相关的知识都是从这位dalao博客里面学的,下面这篇东西是自己对其博客学习后的一些总结和想法,大部分是按照其博客里 ...

  8. 【BZOJ3625】【codeforces438E】小朋友和二叉树 生成函数+多项式求逆+多项式开根

    首先,我们构造一个函数$G(x)$,若存在$k∈C$,则$[x^k]G(x)=1$. 不妨设$F(x)$为最终答案的生成函数,则$[x^n]F(x)$即为权值为$n$的神犇二叉树个数. 不难推导出,$ ...

  9. FFT模板 生成函数 原根 多项式求逆 多项式开根

    FFT #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> ...

随机推荐

  1. Java开发笔记(一百五十)C3P0连接池的用法

    JDBC既制定统一标准兼容了多种数据库,又利用预报告堵上了SQL注入漏洞,照理说已经很完善了,可是人算不如天算,它在性能方面不尽如人意.问题出在数据库连接的管理上,按照正常流程,每次操作完数据库,都要 ...

  2. svn-疑难解决

    Linux下搭建SVN服务器 https://blog.51cto.com/19940919/2095011 [SVN]出现SVN--Authorization failed错误原因 https:// ...

  3. Net Core 自定义 Middleware 加密解密

    前言:第一次写文章,有问题请轻喷 当前使用 Net Core 版本 2.1.3 我们经常在开发中需要把实体的主键 Id 传输到前端,但是在Get的时候又不想让前端能看到明文,我们通常会加密这些数据,所 ...

  4. 2019 前程无忧java面试笔试题 (含面试题解析)

    本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.前程无忧等公司offer,岗位是Java后端开发,最终选择去了前程无忧. 面试了很多家公司,感觉大部分公司考察的点 ...

  5. sense chrome扩展工具安装问题

    下载一个chrome的插件,只能在国内下了.有个什么插件网 .下载完之后是  .crx 格式的.直接拖到 chrome的扩展工具里,显示,插件有问题.无语 参考了一个网上的教程. 1.先将扩展名 .c ...

  6. Jmeter学习笔记(二十三)——生成HTML性能报告

    有时候我们写性能报告的时候需要一些性能分布图,JMeter是可以生成HTML性能报告的.这篇博客,简单介绍下在利用jmeter进行性能测试时,是如何生成HTML的可视化测试报告的 一.准备工作 1:j ...

  7. Flask整合WebLoader 用于大附件拆分上传再合并

    博客:https://blog.csdn.net/jinixin/article/details/77545140 github:https://github.com/jinixin/upload-d ...

  8. 【DATAGUARD】物理dg的switchover切换(五)

    [DATAGUARD]物理dg的switchover切换(五) 一.1  BLOG文档结构图 一.2  前言部分 一.2.1  导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其 ...

  9. selenium 滚动屏幕操作+上传文件

    执行js脚本来滚动屏幕: (x,y)x为0 纵向滚动,y为0横向滚动 负数为向上滚动 driver.execute_script('window.scrollBy(0,250)') 上传文件: 1.导 ...

  10. 【RocketMQ异常】Caused by: com.aliyun.openservices.shade.com.alibaba.rocketmq.client.exception.MQClientException: No route info of this topic, message-service-topic-testf

    一.异常信息 -- ::-thread-] ERROR c.x.x.r.service.producer.ali.AliMQProducerProcess.sendMessageFromQueue(A ...