[模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂
多项式
多项式
形如
\]
这里的多项式实际上指的是形式幂级数, 也就是 \(\mathrm R[[x]]\), 因为我们只关注它每一项的系数.
牛顿迭代法
给定定义域为多项式的函数 \(G(x)\), 求多项式 \(F(x)\), 使得
\]
考虑倍增求出. 如果现在求出了低 \({\lceil \frac n2 \rceil}\) 项的系数, 即
\]
, 那么利用泰勒展开可以得到
\]
求逆
求 \(F(x)\), 满足 \(F(x)A(x) \equiv 1 \pmod{x^n}\).
设 \(A(x)\) 为原函数, 那么 \(G(F(x)) = A(x) - \frac{1}{F(x)}\).
带入 \((1)\),
F(x) & \equiv F_0(x)-\frac{A(x) - F(x)^{-1}}{F(x)^{-2}} & \pmod{x^n} \\
& \equiv F_0(x)-A(x)F_0^2(x)+F_0(x) \\
& \equiv F_0(x)(2-(A(x)F_0(x)) \\
\end{aligned}
\]
多项式有逆的充要条件是常数项 \(a_0 \not = 0\), 递归终点 \(f_0 = a_0^{-1}\).
还可以设 \(G(F(x)) = F(x)A(x) - 1\), 推导略有不同:
带入 \((1)\), 即
\]
由于\(A(x)F_0(x) - 1\) 的低 \(\frac n2\) 位均为 \(0\), 那么在模 \(x^n\) 意义下, 它乘上的数只需考虑低 \(\frac n2\) 位即可.
而 \(A(x)F_0(x)\) 的低 \(\frac n2\) 位中, 只有常数项为 \(1\), 其他项为 \(0\). 那么
\]
上面的式子就可以化为
F(x) & \equiv F_0(x)-\frac{A(x)F_0(x)-1}{A(x)} & \pmod{x^n} \\
& \equiv F_0(x)-\frac{(A(x)F_0(x)-1)F_0(x)}{A(x)F_0(x)} \\
& \equiv F_0(x)-{(A(x)F_0(x)-1)F_0(x)} \\
& \equiv F_0(x)(2-(A(x)F_0(x)) \\
\end{aligned}
\]
倍增即可求解.
求对数
求 \(F(x)\), 满足 \(F(x) \equiv \ln A(x) \pmod{x^n}\).
F(x)
& \equiv \ln A(x) & \pmod{x^n} \\
& \equiv \int \frac{A'(x)}{A(x)} \, \mathrm d x
\end{aligned}
\]
多项式可以求对数的充要条件是常数项 \(a_0 \not = 0\), 经过积分得到常数项为 \(0\).
容易发现在求 \(\ln\) 过程中 \(A(x)\) 的常数项被消成了 \(1\) (分子分母约分).
这里的求对数其实是假设 \(a_0 = 1\), 因为在模意义下, \(\ln x\) 在 \(x \not = 1\) 处无定义.
求指数
求 \(F(x)\), 满足 \(F(x) \equiv e^{A(x)} \pmod{x^n}\).
设
\]
那么, 通过牛顿迭代
\]
多项式可以求指数的充要条件是常数项 \(a_0 = 0\), 递归终点 \(f_0 = 1\).
快速幂
求 \(F(x)\), 满足 \(F(x) \equiv A^k(x) \pmod{x^n}\). \(k\) 可为 (模意义下有意义的) 任意有理数.
F(x)
& \equiv A^k(x) & \pmod{x^n} \\
& \equiv e^{k \ln A(x)}
\end{aligned}
\]
由于 \(\ln\) 过程的限制, 这个过程其实假设了 \(a_0 = 1\).
如果 \(a_0\) 为 \(> 1\) 正整数, 那么设多项式 \(\exp\) 的递归终点为 \(f_0 = a_0^k\) (模意义下; 如果 \(k\) 为分数或负数需要求高次剩余/逆元) 即可;
如果 \(a_0 = 0\), 需要化为 \(A'(x) = \frac{A(x)}{x^l}\), 其中 \(A'(x)\) 常数项不为 \(0\). 答案则为 \((A'(x))^k \cdot x^{lk}\).
多点求值
过于难写... 推荐秦九韶算法, 时间复杂度 \(O(n^2)\).
快速插值
给定 \((x_i, y_i) , \forall i \in \{1,2,\dotsc n\}\), 求一个 \(n-1\) 次多项式 \(F(x)\), 满足 \(F(x_i) \equiv y_i \pmod p\).
同上... 不想写快速插值...
拉格朗日插值
\]
求单点值的时间复杂度 \(O(n^2)\).
拉格朗日反演
设\(F(x)\), \(G(x)\)是形式幂级数, 满足 \(F(G(x))=x\), 称 \(F(x)\) 为 \(G(x)\) 的复合逆.
根据形式幂级数的性质, 可以得到 \(F(x)\) 常数项为 \(0\), 并且 \(G(F(x)) = x\).
可以证明
\]
如果有 \(F(x) = \frac{x}{H(x)}\), 还有
\]
这个过程实际上是求 \(\frac{F(x)}{x}\) 的逆的 \(n\) 次幂. 多项式求逆, 快速幂即可.
另外, 给定另一个多项式 \(A(x)\), 还可以求多项式的复合:
\]
实现的细节
- 长度为
n
, 次数为n-1
- 数组长度为超过
2*n
的2的幂 - 必要时要清空
- 不要忘记取模!
代码
多项式全家桶:
const int nsz=4e5+50;
const ll nmod=998244353,g=3,ginv=332748118;
//998244353 g=3
//1004535809 g=3
int n;
ll a[nsz],b[nsz],ans[nsz];
ll qp(ll a,ll b=nmod-2){
ll res=1;
for(;b;b>>=1,a=a*a%nmod)if(b&1)res=res*a%nmod;
return res;
}
namespace npoly{
//l means length of array
ll len,l2,rev[nsz];
il void cp(ll *a,ll *b,int l0,int l1){
memcpy(a,b,l0*sizeof(ll));
memset(a+l0,0,(l1-l0)*sizeof(ll));
}
il void fftinit(int l0){
l2=0,len=1;
while(len<l0)++l2,len<<=1;
rep(i,0,len-1)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l2-1));//
}
void dft(ll *a,int l,int fl){
rep(i,0,l-1)if(i<rev[i])swap(a[i],a[rev[i]]);
for(int i=1;i<l;i<<=1){
ll wn=qp(fl==1?g:ginv,(nmod-1)/(i<<1));
for(int j=0,p=i<<1;j<l;j+=p){
ll w=1;
for(int k=0;k<i;++k,w=w*wn%nmod){
ll x=a[j+k],y=w*a[j+k+i]%nmod;
a[j+k]=(x+y)%nmod,a[j+k+i]=(x-y)%nmod;
}
}
}
if(fl==-1){
ll v=qp(l);
rep(i,0,l-1)a[i]=a[i]*v%nmod;
}
}
void mul(ll *a,int l1,ll *b,int l2,ll *c,int l3=-1){
if(l3==-1)l3=l1+l2-1;
static ll c1[nsz],c2[nsz];
fftinit(l1+l2-1);
cp(c1,a,l1,len),cp(c2,b,l2,len);
dft(c1,len,1),dft(c2,len,1);
rep(i,0,len-1)c1[i]=c1[i]*c2[i]%nmod;
dft(c1,len,-1);
cp(c,c1,l3,l3);
}
void inv(ll *a,int l,ll *b){
if(l==1){b[0]=qp(a[0]);return;}
int l0=(l+1)>>1;
inv(a,l0,b);
static ll c1[nsz],c2[nsz];
fftinit(l<<1);//需要两倍长度dft保证乘法正确
cp(c1,a,l,len),cp(c2,b,l0,len);
dft(c1,len,1),dft(c2,len,1);
rep(i,0,len-1)c1[i]=c2[i]*(2-c1[i]*c2[i]%nmod)%nmod;
dft(c1,len,-1);
cp(b,c1,l,l);
}
void deriv(ll *a,int l,ll *b){ //b could be eq to a
rep(i,0,l-2)b[i]=a[i+1]*(i+1)%nmod;
b[l-1]=0;
}
void integ(ll *a,int l,ll *b){
repdo(i,l-2,0)b[i+1]=a[i]*qp(i+1)%nmod;
b[0]=0;
}
//a[0] should be 1
void ln(ll *a,int l,ll *b){
static ll c1[nsz],c2[nsz];
inv(a,l,c1),deriv(a,l,c2);
mul(c1,l,c2,l,b,l);
integ(b,l,b);
}
//a[0] should be 0
ll expzero=1;
void exp(ll *a,int l,ll *b){
if(l==1){b[0]=expzero;return;}
int l0=(l+1)>>1;
exp(a,l0,b);
static ll c1[nsz],c2[nsz];
fftinit(l<<1);
rep(i,l0,l-1)b[i]=0;
ln(b,l,c1);
rep(i,0,l-1)c1[i]=(a[i]-c1[i]+(i==0))%nmod;
rep(i,l,len-1)c1[i]=0;
cp(c2,b,l0,len);
dft(c1,len,1),dft(c2,len,1);
rep(i,0,len-1)c1[i]=c1[i]*c2[i]%nmod;
dft(c1,len,-1);
cp(b,c1,l,l);
}
void pow(ll *a,int l,ll p,ll *b){//suppose a[0]!=0;
static ll c[nsz];
ln(a,l,c);
rep(i,0,l-1)c[i]=c[i]*p%nmod;
// expzero=qp(a[0],p);
exp(c,l,b);
}
void sqrt(ll *a,int l,ll *b){pow(a,l,qp(2),b);}
void dncfft(ll *a,int l0,ll *b){
static ll c1[nsz];
rep(i,0,l0-1)c1[i]=-a[i];
c1[0]=(c1[0]+1)%nmod;
inv(c1,l0,b);
}
//tests
void testfft(){
int n,m;
cin>>n>>m,++n,++m;
rep(i,0,n-1)cin>>a[i];
rep(i,0,m-1)cin>>b[i];
mul(a,n,b,m,ans);
rep(i,0,n+m-2)cout<<(ans[i]+nmod)%nmod<<' ';
cout<<'\n';
}
//3 1 2 1
//1 -2 3
void testinv(){
int n;
cin>>n;
rep(i,0,n-1)cin>>a[i];
inv(a,n,ans);
rep(i,0,n-1)cout<<(ans[i]+nmod)%nmod<<' ';
cout<<'\n';
}
void testdnc(){
int n;
cin>>n;
rep(i,1,n-1)cin>>a[i];
dncfft(a,n,ans);
rep(i,0,n-1)cout<<(ans[i]+nmod)%nmod<<' ';
cout<<'\n';
}
//3 1 2 1
//0 2 -1
void testln(){
int n;
cin>>n;
rep(i,0,n-1)cin>>a[i];
ln(a,n,ans);
rep(i,0,n-1)cout<<(ans[i]+nmod)%nmod<<' ';
cout<<'\n';
}
//3 0 1 2
//1 1 499122179(5/2)
void testexp(){
int n;
cin>>n;
rep(i,0,n-1)cin>>a[i];
exp(a,n,ans);
rep(i,0,n-1)cout<<(ans[i]+nmod)%nmod<<' ';
cout<<'\n';
}
void testsq(){
int n;
cin>>n;
rep(i,0,n-1)cin>>a[i];
sqrt(a,n,ans);
rep(i,0,n-1)cout<<(ans[i]+nmod)%nmod<<' ';
cout<<'\n';
}
void testpow(){
int n,k;
cin>>n>>k;
rep(i,0,n-1)cin>>a[i];
pow(a,n,k,ans);
rep(i,0,n-1)cout<<(ans[i]+nmod)%nmod<<' ';
cout<<'\n';
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
npoly::testexp();
return 0;
}
拉格朗日插值:
pair<ll,ll> li[nsz];
ll lag(ll x){
sort(li+1,li+n+1);
n=unique(li+1,li+n+1)-li-1;
ll res=0;
rep(i,1,n){
ll tmp=1;
rep(j,1,n)if(i!=j)tmp=tmp*(li[i].first-li[j].first)%nmod;
tmp=inv(tmp)*li[i].second%nmod;
rep(j,1,n)if(i!=j)tmp=tmp*(x-li[j].first)%nmod;
res=(res+tmp)%nmod;
}
return res;
}
[模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂的更多相关文章
- 多项式求逆/分治FFT 学习笔记
一.多项式求逆 给定一个多项式 \(F(x)\),请求出一个多项式 \(G(x)\), 满足 \(F(x) * G(x) \equiv 1 ( \mathrm{mod\:} x^n )\).系数对 \ ...
- bzoj 3456 城市规划 多项式求逆+分治FFT
城市规划 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1091 Solved: 629[Submit][Status][Discuss] Desc ...
- 【Uoj34】多项式乘法(NTT,FFT)
[Uoj34]多项式乘法(NTT,FFT) 题面 uoj 题解 首先多项式乘法用\(FFT\)是一个很久很久以前就写过的东西 直接贴一下代码吧.. #include<iostream> # ...
- CF848E Days of Floral Colours——DP+多项式求逆/分治NTT
官方题解:http://codeforces.com/blog/entry/54233 就是由简入繁 1.序列处理,只考虑一个半圆 2.环形处理(其实这个就是多了旋转同构) 然后基于分割线邻居的跨越与 ...
- 洛谷.3803.[模板]多项式乘法(FFT)
题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. 5.4 又看了一遍,这个也不错. 2019.3.7 叕看了一遍,推荐这个. #inclu ...
- P3803 [模板] 多项式乘法 (FFT)
Rt 注意len要为2的幂 #include <bits/stdc++.h> using namespace std; const double PI = acos(-1.0); inli ...
- 洛谷.3803.[模板]多项式乘法(NTT)
题目链接:洛谷.LOJ. 为什么和那些差那么多啊.. 在这里记一下原根 Definition 阶 若\(a,p\)互质,且\(p>1\),我们称使\(a^n\equiv 1\ (mod\ p)\ ...
- hdu 5730 Shell Necklace [分治fft | 多项式求逆]
hdu 5730 Shell Necklace 题意:求递推式\(f_n = \sum_{i=1}^n a_i f_{n-i}\),模313 多么优秀的模板题 可以用分治fft,也可以多项式求逆 分治 ...
- FFT模板(多项式乘法)
FFT模板(多项式乘法) 标签: FFT 扯淡 一晚上都用来捣鼓这个东西了...... 这里贴一位神犇的博客,我认为讲的比较清楚了.(刚好适合我这种复数都没学的) http://blog.csdn.n ...
随机推荐
- 从URL到看到网页的过程
从我们输入URL并按下回车键到看到网页结果之间发生了什么?换句话说,一张网页,要经历怎样的过程,才能抵达用户面前?下面来从一些细节上面尝试一下探寻里面的秘密. 前言:键盘与硬件中断 说到输入URL,当 ...
- 原生JS编写兼容IE6,7,8浏览器无缝自动轮播(带按钮切换)
项目要求页面兼容IE6,7,8等浏览器,我们可能会遇到这个轮播效果,轮播板块要求:无限循环.自动轮播和手动切换功能,每一次滚动一小格,网上有很多这类插件,例如:swiper等! 但是很多都是不兼容IE ...
- laravel项目thinksns-plus安装出现RuntimeException Symlink from * to * failed错误
今天xshell安装thinksns-plus的laravel项目时出现了一个错误, [RuntimeException] Symlink from "/root/www.z5w.net/t ...
- Java 8 的Lambda表达式
第一次看到用lambda表达式写出来的Java代码时,我对这种神秘的语法感到非常不理解,认为这样的Java搞得不可读.没有专门的去学习和认识,今天花了几个小时写了示例的练习后,我开心的看到了更清晰的J ...
- python 第二百零八天 ----算法相关
查找方法 : 顺序查找法 二分查找法 import time,random #时间计算 def cal_time(func): def wrapper(*args,**kwargs) ...
- c/c++ 重载运算符 类型转换运算符
重载运算符 类型转换运算符 问题:能不能把一个类型A的对象a,转换成另一个类型B的对象b呢?? 是可以的.这就必须要用类型A的类型转换运算符(conversion operator) 下面的opera ...
- linux 硬盘满了如何处理(转)
linux 硬盘满了如何处理 事件源于在服务器运行一个脚本程序… 好好的脚本突然报错,还以为脚本出现问题了.细看报错原因(具体报错信息已经忘记了),是没有可用空间.从没遇见过这个情况,怎么办呢? 一. ...
- 《Effective Java中文版第二版》读书笔记
说明 这里是阅读<Effective Java中文版第二版>的读书笔记,这里会记录一些个人感觉稍微有些重要的内容,方便以后查阅,可能会因为个人实力原因导致理解有误,若有发现欢迎指出.一些个 ...
- Enterprise Architect 时序图
添加时序图 1,在类图下面新建包 添加sequence时序图 点击流程控制,可以打开流程控制设计界面 我选择的是Lifeline线,你可以选择都差不多. 点击其中一条liftline连到其他上面 双击 ...
- threejs学习笔记(二)
THREE.WebGLRenderer THREE.Scene THREE.OrthographicCamera正交相机 THREE.PerspectiveCamera透视相机 renderer.se ...