hello,polynomial!
设$f_i$表示权值为$i$的树有多少种,权值集合为$S$,那么$\begin{align*}f_i=1+\sum\limits_{j=0}^i[i-j\in S]\sum\limits_{k=0}^jf_kf_{j-k}\end{align*}$(枚举根节点的权值,再枚举左右儿子的权值,还有仅有一点的情况)
这是一个卷积再卷积,用生成函数处理会很方便,设$\begin{align*}F(x)=\sum\limits_{i=0}^\infty f_ix^i,G(x)=\sum\limits_{i=0}^\infty[i\in S]x^i\end{align*}$,那么$F(x)=G(x)F^2(x)+1$
我们已经知道$G(x)$了,现在要求$F(x)$,上式是关于$F(x)$的一元二次方程,直接解,$F(x)=\dfrac{1\pm\sqrt{1-4G(x)}}{2G(x)}$,因为$G(0)=0,F(0)=0$,所以我们取$F(x)=\dfrac{1-\sqrt{1-4G(x)}}{2G(x)}=\dfrac2{1+\sqrt{1-4G(x)}}$
要对多项式开平方根和除法?
只能说一开始发展多项式全家桶的人是个人才...
多项式求逆:给定$F(x)$,求$G(x)$满足$F(x)G(x)\equiv1\ (\text{mod }x^n)$
我们采用倍增的思想:假设已经求出了$G(x)$使得$F(x)G(x)\equiv1(\text{mod }x^n)$,我们要求$H(x)$使得$F(x)H(x)\equiv1(\text{mod }x^{2n})$
$\begin{align*}F(x)G(x)&\equiv1(\text{mod }x^n)\\F(x)G(x)-1&\equiv0(\text{mod }x^n)\\\left(F(x)G(x)-1\right)^2&\equiv0(\text{mod }x^{2n})\\F^2(x)G^2(x)-2F(x)G(x)+1&\equiv0(\text{mod }x^{2n})\\F(x)G^2(x)-2G(x)+H(x)&\equiv0(\text{mod }x^{2n})\\H(x)&\equiv G(x)\left(2-F(x)G(x)\right)(\text{mod }x^{2n})\end{align*}$
每层用FFT求多项式乘法,总时间复杂度为$T(n)=T\left(\dfrac n2\right)+O(n\log_2n)=O(n\log_2n)$
多项式开根:给定$F(x)$,求$G(x)$满足$G^2(x)\equiv F(x)(\text{mod }x^n)$
倍增:假设已求得$G(x)$使$G^2(x)\equiv F(x)(\text{mod }x^n)$,我们要求$H(x)$使得$H^2(x)\equiv F(x)(\text{mod }x^{2n})$
$\begin{align*}G^2(x)&\equiv F(x)(\text{mod }x^n)\\G^2(x)-F(x)&\equiv0(\text{mod }x^n)\\\left(G^2(x)-F(x)\right)^2&\equiv0(\text{mod }x^{2n})\\\left(G^2(x)+F(x)\right)^2&\equiv4G^2(x)F(x)(\text{mod }x^{2n})\\\left(G^2(x)+F(x)\right)^2&\equiv4G^2(x)H^2(x)(\text{mod }x^{2n})\\G^2(x)+F(x)&\equiv2G(x)H(x)(\text{mod }x^{2n})\\H(x)&\equiv\dfrac12\left(\dfrac{F(x)}{G(x)}+G(x)\right)(\text{mod }x^{2n})\end{align*}$
每层要FFT和多项式求逆,时间复杂度还是$O(n\log_2n)$(毒瘤时间复杂度),只不过常数特别大
注意写多项式相关的时候,没用到的项FFT之前一定要置$0$(不要以为不用到高次系数就可以不管)
然后这题就做完了,还是很愉悦的2333
#include<stdio.h>
#include<string.h>
const int mod=998244353,inv2=499122177;
typedef long long ll;
int mul(int a,int b){return a*(ll)b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
int pow(int a,int b){
int s=1;
while(b){
if(b&1)s=mul(s,a);
a=mul(a,a);
b>>=1;
}
return s;
}
int rev[300010],N,iN;
void swap(int&a,int&b){a^=b^=a^=b;}
void pre(int n){
int i,k;
for(N=1,k=0;N<n;N<<=1)k++;
for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
iN=pow(N,mod-2);
}
void ntt(int*a,int on){
int i,j,k,t,w,wn;
for(i=0;i<N;i++){
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(i=2;i<=N;i<<=1){
wn=pow(3,(on==1)?(mod-1)/i:(mod-1-(mod-1)/i));
for(j=0;j<N;j+=i){
w=1;
for(k=0;k<i>>1;k++){
t=mul(a[i/2+j+k],w);
a[i/2+j+k]=de(a[j+k],t);
a[j+k]=ad(a[j+k],t);
w=mul(w,wn);
}
}
}
if(on==-1){
for(i=0;i<N;i++)a[i]=mul(a[i],iN);
}
}
int t0[300010];
void getinv(int*a,int*b,int n){
if(n==1){
b[0]=pow(a[0],mod-2);
return;
}
int i;
getinv(a,b,n>>1);
pre(n<<1);
memset(t0,0,sizeof(t0));
for(i=0;i<n;i++)t0[i]=a[i];
ntt(t0,1);
ntt(b,1);
for(i=0;i<N;i++)b[i]=mul(de(2,mul(t0[i],b[i])),b[i]);
ntt(b,-1);
for(i=n;i<N;i++)b[i]=0;
}
int t1[300010],t2[300010];
void sqrt(int*a,int*b,int n){
if(n==1){
b[0]=1;
return;
}
int i;
sqrt(a,b,n>>1);
memset(t2,0,sizeof(t2));
getinv(b,t2,n);
ntt(t2,1);
memset(t1,0,sizeof(t1));
for(i=0;i<n;i++)t1[i]=a[i];
ntt(t1,1);
ntt(b,1);
for(i=0;i<N;i++)b[i]=mul(ad(mul(t1[i],t2[i]),b[i]),inv2);
ntt(b,-1);
for(i=n;i<N;i++)b[i]=0;
}
int a[300010],b[300010];
int main(){
int n,m,N,i,x;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&x);
if(x<=m)a[x]=-4;
}
for(N=1;N<=m;N<<=1);
a[0]=1;
sqrt(a,b,N);
b[0]++;
memset(a,0,sizeof(a));
getinv(b,a,N);
for(i=1;i<=m;i++)printf("%d\n",(mul(a[i],2)+mod)%mod);
}
457

被折叠的 条评论
为什么被折叠?



