[HDU-6854] Kcats
单元检测题,十分没有脑子的我并没有发现单调栈的大小等于笛卡尔树处理到这个点时向左的祖先的个数加一(思考一下处理笛卡尔树时单调栈的操作可以得出),因为 \(N\leq100\) 所以时间复杂度大概在 \(O(N^3)\) 到 \(O(N^4)\) 之间,然后可以使用区间dp,类比MYJ,可以知道状态定义还要塞一维进去,这道题的话就是把这个区间的这颗子树的根节点向左有多少个点加1,也就是把处理到根节点时单调栈的元素数量放进去,转移式子就是 \(dp_{i,j,d}=\sum_{k=i}^j dp_{i,k-1,d}\times dp_{k+1,j,d+1}\times C^{k-i}_{j-i}\)
其中这个组合数的含义就是这个区间一共 \(j-i+1\) 个数,根节点是最小值,要占一个,左子树在剩下 \(j-i\) 个里面选 \(k-i\) 个
code:
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#pragma GCC optimeze(3)
#pragma GCC optimeze(2)
#define PII pair<int, int>
#define pb push_back
#define fi first
#define se second
#define lowbit(x) (x & (-x))
using namespace std;
const int N=1e2+5;
const int M=1e6;
const int mod=1e9+7;
double eps=1e-9;
const int INF=1e14;
int n,a[N],dp[N][N][N],c[N][N];
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int TTT;cin>>TTT;c[0][0]=1;
for(int i=1;i<=N-5;i++){
c[i][0]=1;
for(int j=1;j<=i;j++){
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
while(TTT--){
cin>>n;
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++)cin>>a[i];
for(int len=1;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
for(int k=l;k<=r;k++){
int L=a[k]==-1? 1:a[k],R=a[k]==-1? n:a[k];
for(int d=L;d<=R;d++){
dp[l][r][d]+=(l!=k? dp[l][k-1][d]:1ll)*(r!=k? dp[k+1][r][d+1]:1ll)%mod*c[r-l][k-l];
dp[l][r][d]%=mod;
}
}
}
}
cout<<dp[1][n][1]<<'\n';
}
return 0;
}