专栏文章

题解:P6534 [COCI 2015/2016 #1] UZASTOPNI

P6534题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mipapukp
此快照首次捕获于
2025/12/03 08:55
3 个月前
此快照最后确认于
2025/12/03 08:55
3 个月前
查看原文

思路

这道题是一道十分巧妙的树形DP。
其中 dplx,idpl_{x,i} 表示以结点 xx 为根的子树当中,等差数列的首项为 ii 是否可行。dprx,idpr_{x,i} 表示已结点 xx 为根的子树中等差数列末项为 xx 为根是否可行。其中 dplx,idpl_{x,i} 中的 ii 要满足 ivui \le v_udprx,idpr_{x,i} 中的 ii 要满足 ivui \ge v_u(题目要求当选了一个结点后必须选它的上司,与就是父亲结点)。
那对于 dplx,i=1dpl_{x,i}=1 需要 xx 的一个子节点 yydply,i=1dpl_{y,i}=1。然后发现,如果想要让 dplx,i=1dpl_{x,i}=1,还需要让 yy 的整颗子树能与 xx 组成等差数列,并且必须是与笑话编号比 xx 小的组成,不然它就无法成为等差数列的首项。既然必须是 xx 的首项,那 yy 中就必须是末项。
对于 dprx,idpr_{x,i} 是一样的,只需把上面全都反过来。

Code

CPP
#include<bits/stdc++.h>
using namespace std;
int n,v[20000],h[20000],ne[20000],e[20000],idx,l[20000][200],r[20000][200];
void add(int u,int v){
	e[idx]=v,ne[idx]=h[u],h[u]=idx++;
} 
void dfs(int x){
	vector<int> tl,tr;
	for(int i=h[x];~i;i=ne[i]){
		int j=e[i];
		dfs(j);
		if(v[j]<v[x]) tl.push_back(j);
		if(v[j]>v[x]) tr.push_back(j);
	}
	l[x][v[x]]=1,r[x][v[x]]=1;
	for(int i=v[x]-1;i>=1;i--){
		for(auto p:tl){
			if(l[p][i]){
				for(int j=i;j<v[x];j++){
					if(r[p][j]&&l[x][j+1]){
						l[x][i]=1;
						break;
					}
				}
			}
		} 
	}
	for(int i=v[x]+1;i<=100;i++){
		for(auto p:tr){
			if(r[p][i]){
				for(int j=v[x]+1;j<=i;j++){
					if(l[p][j]&&r[x][j-1]){
						r[x][i]=1;
						break;
					}
				}
			}
		} 
	}
}
int main(){
	memset(h,-1,sizeof(h));
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>v[i];
	}
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		add(u,v);
	}
	dfs(1);
	int lans=0,rans=0;
	for(int i=1;i<=100;i++){
		lans+=l[1][i];
		rans+=r[1][i]; 
	}
	cout<<lans*rans;
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...