清真多项式题
题意
每个点的权值可以在集合$ S$中任取
求点权和恰好为$[1..n]$的不同的二叉树数量
数据范围全是$ 10^5$
$ Solution $
设集合$ S$的生成函数为$ C$
考虑暴力$ DP$,枚举当前根节点的权值以及左右子树的权值
有
$f[0]=1$
$ f[x]=sumlimits_{i=0}^x sumlimits_{j=0}^{x-i}f[i]f[j]·[C[x-i-j]=1]$
化成生成函数形式即为
$ f=C·f^2+1$
其中$+1$是因为$ C$中不含常数项而多项式$ f$中含有值为$ 1$的常数项
二次方程求解得
$f=frac{1 pm sqrt{1-4C}}{2C}$
因为分母没有常数项,分子显然也不应有常数项
即
$f=frac{1 - sqrt{1-4C}}{2C}$
分母没有常数项不能求逆,则分子分母同乘$ 1+ sqrt{1-4c}$得
$ f=frac{2}{1+sqrt{1-4C}}$
直接上多项式开根,求逆的板子即可
时间复杂度$ O(n log n)$
$ my code $
这是一份自带巨大常数的板子
单$ log 10w$需要跑$ 1s+$
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<vector> #define rt register int #define ll long long using namespace std; namespace fast_IO{ const int IN_LEN=10000000,OUT_LEN=10000000; char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1; inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;} inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;} inline void flush(){fwrite(obuf,1,oh-obuf,stdout);} } using namespace fast_IO; //#define getchar() getchar_() //#define putchar(x) putchar_((x)) inline ll read(){ ll x=0;char zf=1;char ch=getchar(); while(ch!='-'&&!isdigit(ch))ch=getchar(); if(ch=='-')zf=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar(' ');} int k,m,n,x,y,z,cnt,ans; namespace poly{ #define p 998244353 vector<int>R; vector<int>get(int n){ vector<int>ret(n); for(rt i=0;i<n;i++)ret[i]=read(); return ret; } void print(const vector<int>A){for(rt i=0;i<A.size();i++)write((A[i]+p)%p),putchar(' ');} int ksm(int x,int y=p-2){ int ans=1; for(rt i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p; return ans; } void NTT(int n,vector<int>&A,int fla){ A.resize(n); for(rt i=0;i<n;i++)if(i>R[i])swap(A[i],A[R[i]]); for(rt i=1;i<n;i<<=1){ int w=ksm(3,(p-1)/2/i); for(rt j=0;j<n;j+=i<<1){ int K=1; for(rt k=0;k<i;k++,K=1ll*K*w%p){ int x=A[j+k],y=1ll*K*A[i+j+k]%p; A[j+k]=(x+y)%p,A[i+j+k]=(x-y)%p; } } } if(fla==-1){ reverse(A.begin()+1,A.end()); int invn=ksm(n); for(rt i=0;i<n;i++)A[i]=1ll*A[i]*invn%p; } } vector<int>Resize(int n,vector<int>A){A.resize(n);return A;} vector<int>Mul(vector<int>x,vector<int>y){ int lim=1,sz=x.size()+y.size()-1; while(lim<=sz)lim<<=1;R.resize(lim); for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1); NTT(lim,x,1);NTT(lim,y,1); for(rt i=0;i<lim;i++)x[i]=1ll*x[i]*y[i]%p; NTT(lim,x,-1);x.resize(sz); return x; } vector<int>Inv(vector<int>A,int n=-1){ if(n==-1)n=A.size(); if(n==1)return vector<int>(1,ksm(A[0])); vector<int>b=Inv(A,(n+1)/2); int lim=1;while(lim<=n+n)lim<<=1;R.resize(lim); for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1); A.resize(n);NTT(lim,A,1);NTT(lim,b,1); for(rt i=0;i<lim;i++)A[i]=1ll*b[i]*(2ll-1ll*A[i]*b[i]%p)%p; NTT(lim,A,-1);A.resize(n); return A; } vector<int>Div(vector<int>A,vector<int>B){ int n=A.size(),m=B.size(); reverse(A.begin(),A.end()); reverse(B.begin(),B.end()); A.resize(n-m+1),B.resize(n-m+1); int lim=1;while(lim<=2*(n-m+1))lim<<=1;R.resize(lim); for(rt i=0;i<lim;i++)R[i]=(R[i>>1]>>1)|(i&1)*(lim>>1); vector<int>ans=Resize(n-m+1,Mul(A,Inv(B))); reverse(ans.begin(),ans.end()); return ans; } vector<int>Add(vector<int>A,vector<int>B){ int len=max(A.size(),B.size());A.resize(len); for(rt i=0;i<len;i++)(A[i]+=B[i])%=p; return A; } vector<int>Sub(vector<int>A,vector<int>B){ int len=max(A.size(),B.size());A.resize(len); for(rt i=0;i<len;i++)(A[i]-=B[i])%=p; return A; } vector<int>Mul(int x,vector<int>A){ for(rt i=0;i<A.size();i++)A[i]=1ll*A[i]*x%p; return A; } vector<int>deriv(vector<int>A){//求导 for(rt i=1;i<A.size();i++)(A[i-1]=1ll*A[i]*i%p); A.pop_back();return A; } vector<int>integ(vector<int>A){//积分 A.push_back(0); for(rt i=A.size()-2;i>=0;i--)A[i+1]=1ll*A[i]*ksm(i+1)%p; A[0]=0;return A; } vector<int>Ln(const vector<int>A){return integ(Resize(A.size()-1,Mul(deriv(A),Inv(A))));} vector<int>Exp(vector<int>A,int n=-1){ if(n==-1)n=A.size(); if(n==1)return vector<int>(1,1); vector<int>A0=Resize(n,Exp(A,(n+1)>>1)); vector<int>now=Resize(n,Ln(A0)); for(rt i=0;i<n;i++)now[i]=(A[i]-now[i])%p;now[0]++; return Resize(n,Mul(A0,now)); } struct cp{ ll a,b,z;//a+bsqrt(z) cp operator *(const cp s)const{ return {(1ll*a*s.a%p+1ll*b*s.b%p*z%p)%p,(1ll*a*s.b%p+1ll*b*s.a)%p,z}; } }; cp ksm(cp x,int y){ cp ans={1,0,x.z}; for(rt i=y;i;i>>=1,x=x*x)if(i&1){ ans=x*ans; } return ans; } int Sqrt(int n){//求二次剩馀 if(ksm(n,(p-1)/2)!=1)return -1; while(1){ x=rand()%p; if(ksm((1ll*x*x%p-n%p+p)%p,(p-1)/2)==1)continue; cp ret=ksm({x,1,(1ll*x*x%p+p-n)%p},(p+1)/2); return min(ret.a,p-ret.a); } } vector<int>GetSqrt(vector<int>A,int n=-1){ if(n==-1)n=A.size(); if(n==1)return vector<int>(1,Sqrt(A[0])); vector<int>ans=Resize(n,GetSqrt(A,n+1>>1)),C(A.begin(),A.begin()+n); return Resize(n,Mul(ksm(2),Add(ans,Mul(Inv(ans),C)))); } vector<int>Pow(vector<int>A,int k){ A[0]=1; return Exp(Mul(k,Ln(A))); } //#undef p }; using namespace poly; int inv[100010],v[100010]; int main(){ m=read();n=read(); vector<int>c(n+1); for(rt i=1;i<=m;i++){ x=read(); if(x<=n)c[x]++; } vector<int>ans=Mul(-4,c);ans[0]++; ans=GetSqrt(ans);ans[0]++; ans=Mul(2,Inv(ans)); for(rt i=1;i<=n;i++)writeln((ans[i]+p)%p); return flush(),0; }