题意
给定 L , R , n , a 1 , … , a x L,R,n,a_1,\dots,a_x L,R,n,a1,…,ax,对于每个整数 L ≤ i ≤ R L\leq i\leq R L≤i≤R,询问有多少符合以下条件的有根树树(有标号,儿子无序);
- 高度为 i i i;
- 节点数为 n n n;
- 没有任何一个子树的大小为 a j a_j aj;
- 节点编号构成一个小根堆(父亲编号小于儿子)。
1 ≤ L ≤ R ≤ n ≤ 500 , 0 ≤ x < n , 2 ≤ a i ≤ n 1\leq L\leq R\leq n\leq 500,0\leq x<n,2\leq a_i\leq n 1≤L≤R≤n≤500,0≤x<n,2≤ai≤n, a i a_i ai 互不相同。答案模 998244353。
题解
令
f
[
i
]
[
j
]
f[i][j]
f[i][j] 为有
i
i
i 个节点,深度不超过
j
j
j 的树的数量,则答案为
f
[
n
]
[
i
]
−
f
[
n
]
[
i
−
1
]
f[n][i]-f[n][i-1]
f[n][i]−f[n][i−1]。
假设这每树内部节点编号相对大小顺序已经确定。
每次转移考虑将一棵树的一个子树拆下来,强制这个子树的根的编号是第二小的(显然这棵树的根编号是最小的)以避免重复计数。
则不考虑
s
i
z
e
∉
a
size\not\in a
size∈a 的话,转移方程为
f
[
i
]
[
j
]
=
∑
k
=
1
i
−
1
f
[
i
−
k
]
[
j
]
⋅
f
[
k
]
[
j
−
1
]
⋅
(
i
−
2
k
−
1
)
f[i][j]=\sum\limits_{k=1}^{i-1}f[i-k][j]\cdot f[k][j-1]\cdot {i-2\choose k-1}
f[i][j]=k=1∑i−1f[i−k][j]⋅f[k][j−1]⋅(k−1i−2)
考虑
s
i
z
e
∉
a
size\not\in a
size∈a时,只需要在转移时把
f
[
k
]
[
j
−
1
]
f[k][j-1]
f[k][j−1] 这项在
k
∈
a
k\in a
k∈a 时看作 0。但是不应将
f
[
i
−
k
]
[
j
]
f[i-k][j]
f[i−k][j] 看作 0,也不应在 DP 时跳过
f
[
i
]
[
j
]
f[i][j]
f[i][j]。
代码:
#include<bits/stdc++.h>
using namespace std;
int getint(){
int ans=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
const int mod=998244353;
template<int n>struct Choose{
int c[n+2][n+2];
Choose(){
c[1][1]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
}
int operator()(int a,int b){
return c[a+1][b+1];
}
};
int n,k;
Choose<500>c;
int f[510][510];
int a[510],p=0;
int main(){
n=getint(),k=getint();
for(int i=0;i<k;i++)a[i]=getint();
sort(a,a+k);
a[k]=0x7f7f7f7f;
int l=getint(),r=getint();
for(int i=1;i<=n;i++)f[0][i]=1;
if(a[0]!=1)for(int i=1;i<=n;i++)f[1][i]=1;
for(int i=2;i<=n;i++){
//if(a.count(i))continue;
for(int j=2;j<=r;j++){
//cout<<"> "<<i<<" "<<j<<endl;
p=0;
for(int k=1;k<=i-1;k++){
if(a[p]==k){
++p;
continue;
}
while(a[p]<k)p++;
f[i][j]+=f[i-k][j]*1ll*f[k][j-1]%mod*c(i-2,k-1)%mod;
f[i][j]%=mod;
}
//cout<<"> "<<i<<" "<<j<<" "<<f[i][j]<<endl;
}
}
if(a[k-1]==n){
for(int i=l;i<=r;i++)printf("0 ");
}else for(int i=l;i<=r;i++){
printf("%d ",(f[n][i]-f[n][i-1]+mod)%mod);
}
return 0;
}