SHOI2015聚变反应炉


数据范围:

  1. (max(c_i)<=1,n100000)
  2. (max(c_i)<=5,n2000)

我太菜了!!!一分都拿不到……

数据范围1:

贪心

优先点亮(c_i=1)的点,发现顺序并不影响(神奇,自己想想吧)

数据范围2:

树形DP

(f[i][0/1],i)点先点亮自己或父亲时,点亮整棵子树的最小代价

(ans=f[1][0])

考虑转移,引入辅助数组(tmp[i])从儿子得到(i)的能量转移,儿子们的最小代价,用滚动数组完成

(f[x][0]=min{tmp[i]+max(0,d_x-i)})

(f[x][1]=min{tmp[i]+max(0,d_x-i-c_{fa})})

(i)为从儿子接受的能量,要除去多余的能量传递

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N1=1e5+4,N2=2004;
int n,mc,ans,d[N1],c[N1];
int f[N2][2],tmp[2][N2*5];
//f 先染自己/父亲的情况下染完子树的最小代价
//tmp 染完子树并接受儿子们j的能量传递的最小代价 
vector<int>e[N1];
void dfs(int x,int fa){
	int s=0,cur=0;
	for(auto v:e[x]){
		if(v==fa)continue;
		dfs(v,x);
		s+=c[v];
	}
	memset(tmp[0],0x3f,sizeof(tmp[0]));
	tmp[0][0]=0;
	for(auto v:e[x]){
		if(v==fa)continue;
		cur^=1;
		memset(tmp[cur],0x3f,sizeof(tmp[cur]));
		for(int j=0;j<=s-c[v];j++){
			tmp[cur][j+c[v]]=min(tmp[cur][j+c[v]],tmp[cur^1][j]+f[v][0]);
			tmp[cur][j]=min(tmp[cur][j],tmp[cur^1][j]+f[v][1]);
		}
	}
	for(int i=0;i<=s;i++){
		f[x][0]=min(f[x][0],tmp[cur][i]+max(0,d[x]-i));
		f[x][1]=min(f[x][1],tmp[cur][i]+max(0,d[x]-i-c[fa]));
	}
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)d[i]=read();
	for(int i=1;i<=n;i++){
		c[i]=read();
		mc=max(mc,c[i]);
	} 
	for(int i=1,u,v;i<n;i++){
		u=read();v=read();
		e[u].push_back(v);e[v].push_back(u);
	}
	if(mc<=1){
		for(int i=1;i<=n;i++)
			if(c[i]==1){
				ans+=d[i];
				d[i]=0;
				for(auto v:e[i])d[v]--;
			}
		for(int i=1;i<=n;i++)
			if(d[i]>0)ans+=d[i];
		cout<<ans;
		return (0-0);
	}
	memset(f,0x3f,sizeof(f));
	dfs(1,0);
	cout<<f[1][0];
	return (0-0);
}
原文地址:https://www.cnblogs.com/aurora2004/p/12566826.html