題目鏈接:傳送門
我們的小朋友很喜歡計算機科學,而且尤其喜歡二叉樹。
考慮一個含有n個互異正整數的序列。如果一棵帶點權的有根二叉樹滿足其所有頂點的權值都在集合中,我們的小朋友就會將其稱作神犇的。並且他認爲,一棵帶點權的樹的權值,是其所有頂點權值的總和。
給出一個整數m,你能對於任意的s(1<=s<=m)計算出權值爲s的神犇二叉樹的個數嗎?請參照樣例以更好的理解什麼樣的兩棵二叉樹會被視爲不同的。
我們只需要知道答案關於取模後的值。
生成函數簡介:傳送門
令表示是否存在一個,滿足。令的生成函數,其中
令表示權值爲的二叉樹的數量,規定。令的生成函數。
考慮用推出,不妨枚舉根節點的權值,然後計算左右孩子的情況數,即:
。(枚舉根節點的權值,計算左右孩子的情況數,因爲規定,所以允許左右孩子爲空)
用表示,即(因爲,所以常數項要+1)
解一元二次方程,得
因爲,所以的常數項應爲。
若,則當 時,,捨去(打不出來……致習)
若,則當 時,,成立。
分子有理化,,然後搞一下多項式開根+求逆即珂。
Ps.式子中的+1是指常數項+1……差點被孫到
毒瘤代碼
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define re register int
#define mod 998244353
#define G 3
#define inv2 499122177
#define invG 332748118
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int fpow(int b,int p) {
int ans=1;
while(p) {
if(p&1) ans=(ll)ans*b%mod;
b=(ll)b*b%mod;
p>>=1;
}
return ans;
}
inline int inv(int x) {
return fpow(x,mod-2);
}
const int Size=4000005;
const int INF=0x3f3f3f3f;
int R[Size];
void NTT(int *a,int n,int type) {
for(re i=0; i<n; i++) {
if(i<R[i]) {
swap(a[i],a[R[i]]);
}
}
for(re i=1; i<n; i<<=1) {
ll gn=fpow(type==1?G:invG,(mod-1)/(i<<1));
for(re j=0; j<n; j+=i<<1) {
ll g=1;
for(re k=0; k<i; k++) {
ll x=a[j+k],y=g*a[i+j+k]%mod;
a[j+k]=(x+y)%mod;
a[i+j+k]=(x-y+mod)%mod;
g=g*gn%mod;
}
}
}
if(type==-1) {
ll iv=inv(n);
for(re i=0; i<n; i++) {
a[i]=(ll)a[i]*iv%mod;
}
}
}
int A[Size],B[Size],ans[Size];
void Inv(int *a,int *b,int n) { //求a的逆
b[0]=inv(a[0]);
int len;
for(len=1; len<(n<<1); len<<=1) {
int lim=len<<1;
for(re i=0; i<len; i++) {
A[i]=a[i];
B[i]=b[i];
}
for(re i=0; i<lim; i++) {
R[i]=(R[i>>1]>>1)|((i&1)*len);
}
NTT(A,lim,1);
NTT(B,lim,1);
for(re i=0; i<lim; i++) {
b[i]=(ll)B[i]*(2ll-(ll)A[i]*B[i]%mod+mod)%mod;
}
NTT(b,lim,-1);
for(re i=len; i<lim; i++) {
b[i]=0;
}
}
for(re i=0; i<len; i++) A[i]=B[i]=0;
for(re i=n; i<len; i++) b[i]=0;
}
void mul(int *a,int *b,int *c,int n) {
int now=1,L=0;
while(now<(n<<1)) {
now<<=1;
L++;
}
for(re i=0; i<now; i++) {
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
}
NTT(a,now,1);
NTT(b,now,1);
for(re i=0; i<now; i++) {
c[i]=(ll)a[i]*b[i]%mod;
}
NTT(c,now,-1);
}
int tmpa[Size],tmpb[Size],tmpc[Size];
void Sqrt(int *a,int *b,int n) {
b[0]=1;
int len;
for(len=1; len<(n<<1); len<<=1) {
int lim=len<<1;
for(re i=0; i<len; i++) {
tmpa[i]=a[i];
}
for(re i=0; i<lim; i++) {
R[i]=(R[i>>1]>>1)|((i&1)*len);
}
Inv(b,tmpb,len);
mul(tmpa,tmpb,tmpc,lim);
for(re i=0; i<lim; i++) {
b[i]=(ll)(b[i]+tmpc[i])*inv2%mod;
}
for(re i=len; i<lim; i++) {
b[i]=0;
}
}
for(re i=0; i<len; i++) tmpa[i]=tmpb[i]=tmpc[i]=0;
for(re i=n; i<len; i++) b[i]=0;
}
int n,m,a[Size],F[Size];
int main() {
n=read();
m=read();
for(re i=0; i<n; i++) {
int x=read();
a[x]=mod-4;
}
a[0]=1;
Sqrt(a,ans,m+1);
ans[0]++;
Inv(ans,F,m+1);
for(re i=1; i<=m; i++) {
printf("%d\n",(ll)F[i]*2%mod);
}
return 0;
}