多项式求逆学习笔记
前言:
今天学习了多项式求逆,总结一下。
这里是网上好的博客
问题:
给定一个多项式\(A(x)\),求出多项式\(B(x)\),使\(A(x)B(x) \equiv 1 \pmod{x^n}\)。
解析:
考虑递推求解,假设我们已经求出\(B'(x)\),使
\[A(x)B'(x) \equiv 1 \pmod{x^{\lceil \frac{n}{2} \rceil}}
\]
又:
\[A(x)B(x) \equiv 1 \pmod{x^n}
\]
所以:
\[B(x)-B'(x) \equiv 0 \pmod{x^{\lceil \frac{n}{2} \rceil}}
\]
将式子两边平方,有:
\[B(x)^2-2B(x)B'(x)+B'(x)^2 \equiv 0 \pmod{x^n}
\]
这里说明为何模数变成了\(n\),设\(G(X)=(B(x)-B'(x))^2\),那么第\(i\)个系数\(a_i = \sum_{j=0}^{i} c_j \times c_{i-j}\),因为原来在\(0\)至\({\lceil {\frac{n}{2}} \rceil}\)中系数\(c_i\)均为0,所以每一项其中必然有一项\(c_i\)为0。
那么我们就得到了递推式:
\[B(x) \equiv 2B'(x)-A(x) B'(x)^2 \pmod{x^n}
\]
FFT优化乘法即可。
时间复杂度:
\[T(n)=T(n/2)+O(nlogn),T(n)=O(nlogn)
\]
代码实现
#include<bits/stdc++.h>
#define N 300005
using namespace std;
const int P=998244353,G=3;
int n,lim,l,a[N],b[N],c[N],r[N];
inline int In(){
char c=getchar(); int x=0,ft=1;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x*ft;
}
inline int power(int x,int k){
int s=1,t=x;
for(;k;k>>=1,t=1ll*t*t%P) if(k&1) s=1ll*s*t%P;
return s;
}
void NTT(int *a,int op) {
for(int i=0;i<lim;++i) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1) {
int Wn=power(G,(P-1)/(i<<1)); if(op<1) Wn=power(Wn,P-2);
for(int j=0;j<lim;j+=(i<<1)) {
int w=1;
for(int k=0;k<i;++k,w=1ll*w*Wn%P) {
int x=a[j+k],y=1ll*w*a[j+k+i]%P;
a[j+k]=(x+y)%P; a[j+k+i]=(x-y+P)%P;
}
}
}
if(op==-1){
int inv=power(lim,P-2);
for(int i=0;i<lim;++i) a[i]=1ll*a[i]*inv%P;
}
}
inline void Sol(int k){
if(k==1){ b[0]=power(a[0],P-2); return; }
Sol((k+1)/2);
lim=1; l=0; while(lim<2*k) lim<<=1,++l;
for(int i=1;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<k;++i) c[i]=a[i]; for(int i=k;i<lim;++i) c[i]=0;
NTT(b,1); NTT(c,1);
for(int i=0;i<lim;++i) b[i]=1ll*(2-1ll*c[i]*b[i]%P+P)%P*b[i]%P;
NTT(b,-1); for(int i=k;i<lim;++i) b[i]=0;
}
int main(){
n=In(); for(int i=0;i<n;++i) a[i]=In(); Sol(n);
for(int i=0;i<n;++i) printf("%d%c",b[i],(i==n-1)?'\n':' ');
return 0;
}
应用
例1.预处理伯努利数。
伯努利数的指数生成函数是:
\[\sum_{i=0}^{\infty}{ B_i \frac{x^i}{ i!} = \frac{x}{e^x-1}= \frac{x}{\sum_{i=0}^{\infty}{ \frac{x^i}{ (i+1)!}} }}$。
然后求出下面多项式的逆就可以得到伯努利数了。
例2.BZOJ3456 城市规划(权限题)
题意:给定$n$,求出$n$个顶点的简单无向连通图的个数。
解析:设$f(n)$表示$n$个顶点的简单无向连通图的个数,$g(n)$表示$n$个顶点的简单无向图的个数,那么显然有:
$$g(n)=2^{C(n,2)}\qquad(1)\]
考虑\(g(n)\)的另一种计算方法,枚举1号点所在连通块的顶点个数,那么有:
\[g(n)=\sum_{i=1}^{n} C(n-1,i-1)\times f(i) \times g(n-i) \qquad (2)
\]
将(1)代入(2),有:
\[2^{C(n,2)}=\sum_{i=1}^{n} C(n-1,i-1)\times f(i) \times 2^{C(n-i,2)}
\]
两边同时除以\((n-1)!\),有:
\[\frac{2^{C(n,2)}}{(n-1)!}=\sum_{i=1}^{n}{\frac{f(i)}{(i-1)!} \frac{2^{C(n-i,2)}}{(n-i)!}}
\]
定义:\(P(x)=\sum_{n=0}^{\infty} \frac{f(n+1)}{n!} x^n\),\(Q(x)=\sum_{n=0}^{\infty} \frac{2^{C(n,2)}}{n!} x^n\),\(G(x)=\sum_{n=0}^{\infty} \frac{2^{C(n+1,2)}}{n!} x^n\)。
那么据上有:
\[G(x)=P(x)Q(x)
\]
因为是求\(P(x)\)的第\(n-1\)项系数,考虑这个等式在模\(x^n\)下的意义:
\[G(x) \equiv P(x)Q(x) \pmod{x^n}
\]
那么有:
\[P(x) \equiv G(x)^{-1}Q(x) \pmod{x^n}
\]
多项式求逆即可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥