[DMOI R2] 暗号

[DMOI R2] 暗号 官方题解

题目简述

给一棵 nn 个节点的树,每个节点有一个权值。要求给这 nn 个节点黑白染色。两个拥有相同颜色的节点中,深度较小的结点的权值加上子树中颜色与它相等的节点初始值。

(题解直接用染色代替暗号)

思路

subtask 1

可以直接 O(2n)O(2^n) 枚举每个点的颜色,然后遍历整棵树,求出当前整棵树的权值和,最后取最大值。时间复杂度为 O(n2n)O(n2^n)

subtask 2

预期时间复杂度 O(n2n2+1)O(n2^{\frac{n}{2}+1})O(n4)O(n^4),未确定具体算法。

subtask 3

对于一条链的情况,我们可以把它当作一维染色前缀和问题来解决。未确定算法,预计时间复杂度 O(nlogn)O(n3)O(nlogn) \sim O(n^3)

subtask 4

我们发现权值没有负数,那将整棵树染上相同的颜色即可,O(n)O(n) 计算最终答案。

subtask 5

对于菊花图,我们将根节点染上黑色,对于其他节点,如果是负数点权,染上白色,否则染上黑色。预计时间复杂度 O(n)O(n)

subtask 6

我们来考虑正解。这里我们可以发现思路应该往树形 dp 上靠。

我们用 00 代表黑色,用 11 代表白色。

我们从下往上开始进行 dp。我们设 fi,j,k,cf_{i,j,k,c} 为将节点 ii 染成颜色 cc,且 ii 到根的路径上有 jj 组连续两个染黑色的点,kk 组连续染白色的点,ii 的子树对答案的贡献。

那么我们有如下的状态转移方程:

fu,j,k,0=vsonumax(fv,j,k,1,fv,j+1,k,0)+(j+1)wufu,j,k,1=vsonumax(fv,j,k,0,fv,j,k+1,1)+(k+1)wuf_{u,j,k,0}=\sum_{v\in son_u}\max(f_{v,j,k,1},f_{v,j+1,k,0})+(j+1)w_u\\ f_{u,j,k,1}=\sum_{v\in son_u}\max(f_{v,j,k,0},f_{v,j,k+1,1})+(k+1)w_u

具体来说,如果点 uu 染成了黑色,其子节点 vv 也为黑色,那么该子节点对子树 ii 的贡献为 fv,j+1,k,0f_{v,j+1,k,0},如果子节点 vv 为白色,那么该子节点对子树 ii 的贡献为 fv,j,k,1f_{v,j,k,1}。如果点 uu 染成了白色,其子节点 vv 也为白色,那么该子节点对子树 ii 的贡献为 fv,j,k+1,1f_{v,j,k+1,1},如果子节点 vv 为黑色,那么该子节点对子树 ii 的贡献为 fv,j,k,0f_{v,j,k,0}。则点 uu 对答案的贡献为其所有子节点对 uu 的贡献加上自己的贡献。我们从下往上 dp,最终答案为 max(f1,0,0,0,f1,0,0,1)\max(f_{1,0,0,0},f_{1,0,0,1})

解题代码

#include<cstdio>
typedef long long ll;
inline int read(){
	int x=0;
	int ch=getchar(),f=0;
	while(ch<48||ch>57) f=(ch=='-'),ch=getchar();
	while(ch>47&&ch<58) x=(x<<3)+(x<<1)+(ch&15),ch=getchar();
	return f?-x:x;
}
const int N=505;
int n;
struct node{
	int to,nxt;
}e[N<<1];
int head[N],cnt;
inline void add(int u,int v){
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
int dep[N];
int s[N],w[N];
inline void dfs1(int u,int f){
	dep[u]=dep[f]+1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==f) continue;
		dfs1(v,u);
	}
}
int f[N][N][N][2];
inline int max(int x,int y){return x>y?x:y;}
inline void dfs2(int u,int fa){
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa) continue;
		dfs2(v,u);
		for(int j=0;j<dep[u];++j){
			for(int k=0;k<dep[u]-j;++k){
				f[u][j][k][0]+=max(f[v][j][k][1],f[v][j+1][k][0]);
				f[u][j][k][1]+=max(f[v][j][k][0],f[v][j][k+1][1]);
			}
		}
	}
	for(int j=0;j<dep[u];++j){
		for(int k=0;k<dep[u]-j;++k){
			f[u][j][k][0]+=(j+1)*w[u];
			f[u][j][k][1]+=(k+1)*w[u];
		}
	}
}
int main(){
	n=read();
	for(int i=1,u,v;i<n;++i){
		u=read(),v=read();
		add(u,v);
		add(v,u);
	}
	dfs1(1,0);
	for(int i=1;i<=n;++i) w[i]=read();
	dfs2(1,0);
	printf("%d\n",max(f[1][0][0][0],f[1][0][0][1]));
	return 0;
}
posted @   June_Failure  阅读(1)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示