[HDU-6854] Kcats (2020多校7 T11) (笛卡尔树+区间dp)

前缀$p_1,p_2,\cdots,p_i$的单调栈大小,即$i$号节点在全局的笛卡尔树上对应的位置的所有在左边的祖先个数

因此,区间$dp$笛卡尔树的树形,合并时,为了满足题目的限制,只需要记录左边的祖先个数$d$

即定义$dp[l][r][d]$为区间$l,r$对应笛卡尔树子树,且根节点左祖先个数为$d$的方案数

合并两个子树时注意补上组合数,且自己这个点对于左儿子深度没有贡献

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
template <class T=int> T rd(){
T s=0; int f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}

const int N=1e2+10,P=1e9+7;

int n,a[N],C[N][N],dp[N][N][N];

int main(){
rep(i,0,N-1) rep(j,C[i][0]=1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
rep(kase,1,rd()) {
rep(i,1,n=rd()) a[i]=rd();
memset(dp,0,sizeof dp);
drep(i,n,1) rep(j,i,n) rep(k,i,j)
rep(d,~a[k]?a[k]:1,~a[k]?a[k]:n)
dp[i][j][d]=(dp[i][j][d]+1ll*(i<k?dp[i][k-1][d]:1)*(k<j?dp[k+1][j][d+1]:1)%P*C[j-i][k-i])%P;
printf("%d\n",dp[1][n][1]);
}
}