前置 skill
基础求导
(全世界应该只有我不会求导了吧……=。=,但考虑到可能有小学生在看这篇文章,所以还是讲一下吧
导数,是微积分中的重要基础概念,关于它的具体内容就不讲了,在本文中,你只要知道,求导是用来拟合一个函数在各处的斜率的东西,并且有:
若 $f(x)=x^{a}$,则 $f'(x)=ax^{a-1}$($f'(x)$:一阶导数)。由此可知,还有 $f”(x)=a(a-1)x^{a-2}$($f”(x)$: 二阶导数)等等。
泰勒展开
将一个函数在 $x_0$处泰勒展开可得:
$$f(x)=f(x_0)+\frac{f'(x_0)}{1!}(x-x_0)+\frac{f”(x_0)}{2!}(x-x_0)^2+…+\frac{f^n(x_0)}{n!}(x-x_0)^n$$
多项式求逆
多项式牛顿迭代
已知 $G(x)$,求解 $G(F(x)) \equiv 0 \pmod{x^n}$
假设已经存在 $G(H(x)) \equiv 0 \pmod{x^{\frac{n}{2}}}$
我们把 $G(F(x))$在 $H(x)$处泰勒展开一下。
又因为 $G(H(x)) \equiv 0 \pmod{x^{\frac{n}{2}}}$,而 $G(F(x)) \equiv 0 \pmod{x^n}$,$G(F(x))$中 $F(x)$次数较小的 $\frac{n}{2}$项在模 $x^n$意义下能够产生的贡献是 0,而 $G$是一个多项式,所以次数较大的 $\frac{n}{2}$项不会影响次数较小的这些项,因此 $F(x)$的前 $\frac{n}{2}$项就是 $H(x)$,则 $F(x)-H(x)$的前 $\frac{n}{2}$项为 0,则 $(F(x)-H(x))^2 \pmod{x^n} \equiv 0$。
则有:
$$G(F(x)) \equiv G(H(x))+G'(H(x))(F(x)-H(x)) \equiv 0 \pmod{x^n}$$
也就是:
$$F(x) \equiv H(x)-\frac{G(H(x))}{G'(H(x))} \pmod{x^n}$$
于是我们可以不断缩小 $n$的规模,同时利用多项式求逆来搞这些东西了。
多项式开根
即求 $F(x)^2 \equiv P(x) \pmod{x^n}$,$P(x)$已知,就是一个常数。
那么我们设 $G(A)=A^2-P$,于是我们就可以利用多项式牛顿迭代的式子来求解 $F(x)$辣。
很容易知道:
$$F(x)=H(x)-\frac{H(x)^2-P(x)}{2H(x)}$$
例题
codeforces 438E/bzoj3625 小朋友和二叉树
我们设 $f(x)$表示权值和为 $x$的二叉树形态个数,设 $a(x)$表示 $c$集合中是否存在权值 $x$,则通过枚举根节点权值和根节点两个叉上子树的权值和,可得一个递推式:
$$f(t)=f(x)f(y)a(t-x-y)$$
边界:$f(0)=1$
也就是说,$f(x)=f(x)^2a(x)+1$
解得:$f(x)=\frac{1±\sqrt{1-4a(x)}}{2a(x)}$
分子分母同时乘以 $1 ∓ \sqrt{1-4a(x)}$,并舍去分母有可能为 0 的那个解可得:
$$f(x)=\frac{2}{1+\sqrt{1-4a(x)}}$$
多项式求逆+开根即可完成本题。
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
const int mod=998244353,N=262150,G=3;
int n,m,inv2;
int A[N],B[N],C[N],rev[N],c[N],tmp[N],len[N];
int ksm(int x,int y) {
int re=1;
for(;y;y>>=1,x=1LL*x*x%mod) if(y&1) re=1LL*re*x%mod;
return re;
}
void NTT(int *a,int n,int x) {
for(RI i=0;i<n;++i) if(rev[i]>i) swap(a[i],a[rev[i]]);
for(RI i=1;i<n;i<<=1) {
int gn=ksm(G,(mod-1)/(i<<1));
for(RI j=0;j<n;j+=(i<<1)) {
int t1,t2,g=1;
for(RI k=0;k<i;++k,g=1LL*g*gn%mod) {
t1=a[j+k],t2=1LL*g*a[j+i+k]%mod;
a[j+k]=(t1+t2)%mod,a[j+i+k]=(t1-t2+mod)%mod;
}
}
}
if(x==1) return;
reverse(a+1,a+n);int inv=ksm(n,mod-2);
for(RI i=0;i<n;++i) a[i]=1LL*a[i]*inv%mod;
}
void getrev(int t)
{for(RI i=0;i<t;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len[t]-1));}
void getinv(int *a,int *b,int n) {
if(n==1) {b[0]=ksm(a[0],mod-2);return;}
getinv(a,b,n>>1);
int kn=n<<1;getrev(kn);
for(RI i=0;i<n;++i) c[i]=a[i],c[n+i]=0;
NTT(c,kn,1),NTT(b,kn,1);
for(RI i=0;i<kn;++i) b[i]=1LL*b[i]*(2-1LL*c[i]*b[i]%mod+mod)%mod;
NTT(b,kn,-1);
for(RI i=n;i<kn;++i) b[i]=0;
}
void getsqrt(int *a,int *b,int n) {
if(n==1) {b[0]=1;return;}
getsqrt(a,b,n>>1);int kn=n<<1;
for(RI i=0;i<n;++i) tmp[i]=0;
getinv(b,tmp,n),getrev(kn);
for(RI i=0;i<n;++i) c[i]=a[i],c[n+i]=0;
NTT(c,kn,1),NTT(b,kn,1),NTT(tmp,kn,1);
for(RI i=0;i<kn;++i) b[i]=1LL*(b[i]+1LL*c[i]*tmp[i]%mod)%mod*inv2%mod;
NTT(b,kn,-1);
for(RI i=n;i<kn;++i) b[i]=0;
}
int main()
{
n=read(),m=read();
for(RI i=1;i<=n;++i) A[read()]=1;
int kn=1;while(kn<=m) kn<<=1,len[kn]=len[kn>>1]+1;
len[kn<<1]=len[kn]+1;
for(RI i=0;i<kn;++i) A[i]=(mod-4LL*A[i]%mod)%mod;
A[0]=1,inv2=ksm(2,mod-2);
getsqrt(A,B,kn),B[0]=(B[0]+1)%mod;
getinv(B,C,kn);
for(RI i=1;i<=m;++i) printf("%d\n",(C[i]+C[i])%mod);
return 0;
}
0 条评论