Progress Monitoring CodeForces - 509F(区间DP,记忆化搜索)

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/81670099

Progress Monitoring

题目链接:CodeForces - 509F

题意:给出一个序列b,b是一棵树dfs下的节点输出顺序,同一层的节点值小的优先搜索;问这棵树有几种结构形式;

思路:dp[i][j]表示i为根i+1~j是其子树的节点,然后就是看i+1~j是否可以再分为多棵树;

假设可以继续分为以i+1, k+1为根的两棵树(i+1, k在同一层) ,则必须满足b[i+1]<b[k+1]或者k==j,如下:

dp[i][j]=\sum_{k=i+1}^{j}((b[i+1]<b[k+1]||k==j)?dp[i+1][k]*dp[k][j]:1)

至于为什么是dp[i+1][k]*dp[k][j],而不是dp[i+1][k]*dp[k+1][j]或者dp[i+1][k-1]*dp[k][j],我也是有点不思其解;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll dp[510][510];//dp[i][j]表示以i为根节点的i+1~j是i的孩子节点, 注:这里的孩子并不指每个节点直接与i相连, 而是i->i+1->i+2->i+3->...->j, 是一条链;
int b[510];
ll dfs(int i, int j){
	if(i==j) return 1;//一个节点可以作为一棵树;
	if(dp[i][j]!=-1) return dp[i][j];//记忆化搜索;
	ll ans=0;
	//遍历i的所有孩子节点, 看能否以其中的节点为根节点, 产生两条链, 判断条件如下:
	//k是最右的节点, 可以单独成为一颗树;
	//b[k+1]>b[i+1], k~j可以单独成树;
	//这里表示从k开始分叉;
	for(int k=i+1; k<=j; k++){
		if(k==j||b[k+1]>b[i+1]){
			ans=(ans+dfs(i+1, k)*dfs(k, j)%mod)%mod;
		}
	}
	dp[i][j]=ans;
	return dp[i][j];
}
int main(){
	int n;
	scanf("%d", &n);
	for(int i=1; i<=n; i++){
		scanf("%d", &b[i]);
	}
	memset(dp, -1, sizeof(dp));
	printf("%lld\n", dfs(1, n));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/81670099
今日推荐