BZOJ 3625: [Codeforces Round #250]小朋友和二叉树
3625: [Codeforces Round #250]小朋友和二叉树
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 343 Solved: 143
[Submit][Status][Discuss]
Description
我们的小朋友很喜欢计算机科学,而且尤其喜欢二叉树。
考虑一个含有n个互异正整数的序列c[1],c[2],...,c[n]。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{c[1],c[2],...,c[n]}中,我们的小朋友就会将其称作神犇的。并且他认为,一棵带点权的树的权值,是其所有顶点权值的总和。
给出一个整数m,你能对于任意的s(1<=s<=m)计算出权值为s的神犇二叉树的个数吗?请参照样例以更好的理解什么样的两棵二叉树会被视为不同的。
我们只需要知道答案关于998244353(7*17*2^23+1,一个质数)取模后的值。
Input
第一行有2个整数 n,m(1<=n<=10^5; 1<=m<=10^5)。
第二行有n个用空格隔开的互异的整数 c[1],c[2],...,c[n](1<=c[i]<=10^5)。
Output
输出m行,每行有一个整数。第i行应当含有权值恰为i的神犇二叉树的总数。请输出答案关于998244353(=7*17*2^23+1,一个质数)取模后的结果。
Sample Input
2 3
1 2
样例二:
3 10
9 4 3
样例三:
5 10
13 10 6 4 15
Sample Output
1
3
9
样例二:
0
0
1
1
0
2
4
2
6
15
样例三:
0
0
0
1
0
1
0
2
0
5
HINT
对于第一个样例,有9个权值恰好为3的神犇二叉树:
Source
分析:
定义$f(x)$为权值为$x$的二叉树个数,$g(x)$为$c$集合中是否存在一个权值为$x$的元素,也就是一个$01$序列...
然后考虑$f$和$g$的关系,$f=f^2g+1$,其中$g$是枚举根节点的权值,$f^2$分别枚举左右子树的权值,$+1$是加上一个空树的情况...
这样我们解出来$f=\frac {1± \sqrt {1-4g}}{2g}$,然后把$g$的生成函数带进去求解即可...
这样就需要多项式求逆和多项式开方...
多项式求逆:
我们考虑倍增的思想,我们现在已经知道了$A(x)B(x)=1 (mod x^m)$,求$C(x)$满足$A(x)C(x)=1 (mod x^{2m})$...
可以得出$C(x)=B(x)(2-A(x)B(x))$...
多项式开方:
依旧是倍增的思想,我们现在已经知道了$B(x)B(x)=A(x) (mod x^m)$,求$C(x)$满足$C(x)C(x)=A(x) (mod x^{2m})$...
可以得出$C(x)=\frac {B^2(x)+A(x)}{2B(x)}$...
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=500000+5,mod=998244353,M=499122177,G=5; int n,L,num,R[maxn],a[maxn],b[maxn],c[maxn],d[maxn]; inline int power(int x,int y){ int res=1; while(y){ if(y&1) res=1LL*res*x%mod; x=1LL*x*x%mod,y>>=1; } return res; } inline void NTT(int *a,int f,int n,int L){ // for(int i=0;i<n;i++) cout<<a[i]<<" ";puts(""); for(int i=0;i<n;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1)); for(int i=0;i<n;i++) if(i<R[i]) swap(a[i],a[R[i]]); for(int i=1;i<n;i<<=1){ int wn=power(G,(mod-1)/(i<<1)); if(f==-1) wn=power(wn,mod-2); for(int j=0;j<n;j+=(i<<1)){ int w=1; for(int k=0;k<i;k++,w=1LL*w*wn%mod){ int x=a[j+k],y=1LL*w*a[j+k+i]%mod; a[j+k]=((x+y)%mod+mod)%mod; a[j+k+i]=((x-y)%mod+mod)%mod; } } } if(f==-1){ int tmp=power(n,mod-2); for(int i=0;i<n;i++) a[i]=1LL*a[i]*tmp%mod; } // for(int i=0;i<n;i++) cout<<a[i]<<" ";puts("");puts(""); } //b(2-a*b) inline void inverse(int *a,int *b,int n,int L){ if(n==1){ b[0]=power(a[0],mod-2);return; } inverse(a,b,n>>1,L-1); memcpy(c,a,n*sizeof(int)); memset(c+n,0,n*sizeof(int)); /*cout<<"inverse: "<<endl;*/NTT(c,1,n<<1,L+1);NTT(b,1,n<<1,L+1); for(int i=0;i<n<<1;i++) b[i]=1LL*b[i]*((2-1LL*c[i]*b[i]%mod+mod)%mod)%mod; /*cout<<"inverse: "<<endl;*/NTT(b,-1,n<<1,L+1); memset(b+n,0,n*sizeof(int)); } //(b^2+a)/(2*b) inline void sqrt(int *a,int *b,int n,int L){ if(n==1){ b[0]=1;return; } sqrt(a,b,n>>1,L-1); memset(d,0,n*2*sizeof(int)); inverse(b,d,n,L); // cout<<"d: "<<endl;for(int i=0;i<n;i++) cout<<d[i]<<" ";cout<<endl; memcpy(c,a,n*sizeof(int)); memset(c+n,0,n*sizeof(int)); /*cout<<"sqrt: "<<endl;*/NTT(c,1,n<<1,L+1),NTT(b,1,n<<1,L+1);NTT(d,1,n<<1,L+1); for(int i=0;i<n<<1;i++) b[i]=(1LL*c[i]*d[i]%mod+b[i])%mod*M%mod; // cout<<"b: "<<endl;for(int i=0;i<n<<1;i++) cout<<b[i]<<" ";cout<<endl; /*cout<<"sqrt: "<<endl;*/NTT(b,-1,n<<1,L+1); memset(b+n,0,n*sizeof(int)); } signed main(void){ // freopen("out.txt","w",stdout); scanf("%d%d",&n,&num);a[0]=1; for(int i=1,x;i<=n;i++){ scanf("%d",&x); if(x<=num) a[x]=mod-4; } for(n=1;n<=num;n<<=1) L++; sqrt(a,b,n,L); memcpy(a,b,n*sizeof(int));a[0]++; memset(b,0,n*sizeof(int));inverse(a,b,n,L); for(int i=1;i<=num;i++) printf("%d\n",(b[i]<<1)%mod); return 0; }
By NeighThorn