多项式板子
_SeeleVollerei_ · · 个人记录
我觉得板子放在学习笔记里太占用空间了,干脆单独出来放一份。
关于原根
常用的原根都是 3 (998244353), 结果
有点像卡常的东西实际上是复杂度问题
期间有很多清空的东西不要用
防止重复变量数组的神奇方法
在函数里开
static int [];
然后这个数组只能在这个函数里用,但是是全局变量,非常神奇。
多项式求导/微分
多项式积分
多项式求逆
已知多项式
把
假设已知
有
则有
两边同时平方
同时乘
则有
递推/递归处理即可。
边界条件:当
多项式求 \ln
已知多项式
两边求个导,左边就是
右边实际上是个复合函数,套一下最上面的公式就是
而
所以原式变成
对
然后对
泰勒展开
假设已知
则有
多项式求 \exp
已知多项式
设
也就是已知多项式
就是多项式复合/牛顿迭代了
对
拆开来就是最后的式子了
写完它
多项式开根
已知多项式
假设已知
则有
即
两边同时平方
将
移一下项可得
多项式快速幂
已知多项式
一开始看到这个式子时,我的反应是这样的:
这不就直接暴力
然后看了一下数据范围
k\le 10^{10^5}
那没事了那没事了还是老老实实推式子吧
想办法把
右边我们是会求的,但是如何把左边的
多项式除法
已知多项式
令
形式化地说,假设
然后有一个很神奇的式子
考虑对于原式
则有
考虑
对两边同时对
则
然后把
在最后放一下自己的板子
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5;
const int Mod=998244353;
const int G=3;
const int INV2=(Mod+1)/2;
inline int Read(){
char ch;
int f=1;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-') f=-1;
int x=ch^48;
while((ch=getchar())>='0'&&ch<='9')
x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
inline void Print(const int x,const char ch='\n',const bool flg=1){
if(x>=10) Print(x/10,ch,0);
putchar(x%10+48);
if(flg) putchar(ch);
return ;
}
inline int Quick_Pow(int a,int b){
int ss=1;
for(;b;b>>=1){
if(b&1) ss=1ll*ss*a%Mod;
a=1ll*a*a%Mod;
}
return ss;
}
inline void Swap(int&x,int&y){
int tmp=x;
x=y;y=tmp;
return ;
}
int rev[N<<3];
inline void NTT(int*p,const int s1,const bool inv){
for(register int i=0;i<s1;i++)
if(i<rev[i]) Swap(p[i],p[rev[i]]);
for(register int mid=1;mid<s1;mid<<=1){
int wn=Quick_Pow(G,(Mod-1)/(mid<<1));
if(inv) wn=Quick_Pow(wn,Mod-2);
for(register int len=mid<<1,i=0;i<s1;i+=len){
int w=1;
for(register int j=0;j<mid;j++,w=1ll*w*wn%Mod){
int a1=p[i+j],a2=p[i+j+mid];
p[i+j]=(a1+1ll*w*a2%Mod)%Mod;
p[i+j+mid]=(a1-1ll*w*a2%Mod+Mod)%Mod;
}
}
}
return ;
}
inline void GetMul(int*f,int*g,const int n,const int m,int*p){
int s1=1,pos=0;
while(s1<=(n+m)) s1<<=1,pos++;
for(register int i=0;i<s1;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1));
NTT(f,s1,0);NTT(g,s1,0);
for(register int i=0;i<s1;i++)
p[i]=1ll*f[i]*g[i]%Mod;
NTT(f,s1,1);NTT(g,s1,1);NTT(p,s1,1);
int inv=Quick_Pow(s1,Mod-2);
for(register int i=0;i<s1;i++){
f[i]=1ll*f[i]*inv%Mod;
g[i]=1ll*g[i]*inv%Mod;
p[i]=1ll*p[i]*inv%Mod;
}
return ;
}
inline void GetDao(int*f,int*g,const int n){
for(register int i=0;i<n-1;i++)
g[i]=1ll*(i+1)*f[i+1]%Mod;
return ;
}
inline void GetJi(int*f,int*g,const int n){
for(register int i=1;i<=n;i++)
g[i]=1ll*f[i-1]*Quick_Pow(i,Mod-2)%Mod;
return ;
}
inline void GetInv(int*f,int*g,const int n){
static int gp[N<<3],tmp[N<<3];
g[0]=Quick_Pow(f[0],Mod-2);
for(register int len=1,t=0;len<n;len<<=1,t++){
int s1=len<<1,pos=t+1;
for(register int i=0;i<s1;i++){
gp[i]=g[i];
tmp[i]=f[i];
}
s1<<=1,pos++;
for(register int i=len<<1;i<s1;i++)
gp[i]=tmp[i]=0;
for(register int i=0;i<s1;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1));
NTT(gp,s1,0);NTT(tmp,s1,0);
for(register int i=0;i<s1;i++){
g[i]=2*gp[i]%Mod;
int gl=1ll*gp[i]*gp[i]%Mod*tmp[i]%Mod;
g[i]=(g[i]-gl+Mod)%Mod;
}
NTT(g,s1,1);
int inv=Quick_Pow(s1,Mod-2);
for(register int i=0;i<s1;i++)
g[i]=1ll*g[i]*inv%Mod;
for(register int i=len<<1;i<s1;i++)
g[i]=0;
}
return ;
}
inline void GetLn(int*f,int*g,const int n){
static int finv[N<<3],fdao[N<<3],gdao[N<<3];
GetDao(f,fdao,n);
GetInv(f,finv,n);
int s1=1,pos=0;
while(s1<=(n<<1)) s1<<=1,pos++;
for(register int i=n;i<s1;i++)
fdao[i]=finv[i]=0;
for(register int i=0;i<s1;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1));
NTT(fdao,s1,0);NTT(finv,s1,0);
for(register int i=0;i<s1;i++)
gdao[i]=1ll*fdao[i]*finv[i]%Mod;
NTT(gdao,s1,1);
int inv=Quick_Pow(s1,Mod-2);
for(register int i=0;i<s1;i++)
gdao[i]=1ll*gdao[i]*inv%Mod;
GetJi(gdao,g,n);
return ;
}
inline void GetExp(int*f,int*g,const int n){
static int gp[N<<3],gpln[N<<3],tmp[N<<3];
g[0]=1;
for(register int len=1,t=0;len<(n<<1);len<<=1,t++){
int s1=len<<1,pos=t+1;
for(register int i=0;i<s1;i++){
gp[i]=g[i];
tmp[i]=f[i];
gpln[i]=0;
}
GetLn(gp,gpln,len);
s1<<=1,pos++;
for(register int i=len<<1;i<s1;i++)
gp[i]=tmp[i]=gpln[i]=0;
for(register int i=0;i<s1;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1));
NTT(gp,s1,0);NTT(gpln,s1,0);NTT(tmp,s1,0);
for(register int i=0;i<s1;i++){
int gl=(gpln[i]-tmp[i]+Mod)%Mod;
g[i]=(gp[i]-1ll*gl*gp[i]%Mod+Mod)%Mod;
}
NTT(g,s1,1);
int inv=Quick_Pow(s1,Mod-2);
for(register int i=0;i<s1;i++)
g[i]=1ll*g[i]*inv%Mod;
for(register int i=len<<1;i<s1;i++)
g[i]=0;
}
return ;
}
inline void GetSqr(int*f,int*g,const int n){
static int gp[N<<3],gpinv[N<<3],tmp[N<<3];
g[0]=1;
for(register int len=1,t=0;len<(n<<1);len<<=1,t++){
int s1=len<<1,pos=t+1;
for(register int i=0;i<s1;i++){
gp[i]=g[i];
tmp[i]=f[i];
}
GetInv(gp,gpinv,len);
s1<<=1,pos++;
for(register int i=len<<1;i<s1;i++)
gp[i]=tmp[i]=gpinv[i]=0;
for(register int i=0;i<s1;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1));
NTT(gp,s1,0);NTT(tmp,s1,0);NTT(gpinv,s1,0);
for(register int i=0;i<s1;i++){
g[i]=(tmp[i]+1ll*gp[i]*gp[i]%Mod)%Mod;
g[i]=1ll*g[i]*INV2%Mod*gpinv[i]%Mod;
}
NTT(g,s1,1);
int inv=Quick_Pow(s1,Mod-2);
for(register int i=0;i<s1;i++)
g[i]=1ll*g[i]*inv%Mod;
for(register int i=len<<1;i<s1;i++)
g[i]=0;
}
return ;
}
inline void GetPow(int*f,int*g,const int n,const int k){
static int fln[N<<3];
GetLn(f,fln,n);
for(register int i=0;i<n;i++)
fln[i]=1ll*fln[i]*k%Mod;
GetExp(fln,g,n);
return ;
}
inline void GetDiv(int*A,int*B,int*f,const int n,const int m){
static int Binv[N<<3];
reverse(A,A+n+1);
reverse(B,B+m+1);
GetInv(B,Binv,n-m+1);
int s1=1,pos=0;
while(s1<=(2*n-m+2)) s1<<=1,pos++;
for(register int i=n-m+1;i<s1;i++)
Binv[i]=0;
for(register int i=0;i<s1;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1));
NTT(A,s1,0);NTT(Binv,s1,0);
for(register int i=0;i<s1;i++)
f[i]=1ll*A[i]*Binv[i]%Mod;
NTT(A,s1,1);NTT(f,s1,1);
int inv=Quick_Pow(s1,Mod-2);
for(register int i=0;i<s1;i++){
A[i]=1ll*A[i]*inv%Mod;
f[i]=1ll*f[i]*inv%Mod;
}
reverse(A,A+n+1);
reverse(B,B+m+1);
reverse(f,f+n-m+1);
return ;
}
inline void GetMod(int*A,int*B,int*g,const int n,const int m){
static int f[N<<3];
GetDiv(A,B,f,n,m);
int s1=1,pos=0;
while(s1<=(n+2)) s1<<=1,pos++;
for(register int i=0;i<s1;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(pos-1));
NTT(A,s1,0);NTT(B,s1,0);NTT(f,s1,0);
for(register int i=0;i<s1;i++)
g[i]=(A[i]-1ll*B[i]*f[i]%Mod+Mod)%Mod;
NTT(A,s1,0);NTT(B,s1,0);NTT(g,s1,1);
int inv=Quick_Pow(s1,Mod-2);
for(register int i=0;i<s1;i++){
A[i]=1ll*A[i]*inv%Mod;
B[i]=1ll*B[i]*inv%Mod;
g[i]=1ll*g[i]*inv%Mod;
}
return ;
}