LGP3354题解

太厉害了。。。

首先看到这种题第一眼就是 DP,\(dp[u][k]\) 表示 \(u\) 子树有 \(k\) 个伐木场。

然后发现不会计算贡献。不会计算贡献可以考虑加状态强制算贡献,或者提前计算费用。

很容易想到的是 \(dp[u][m][k]\) 表示在上面状态的基础上加一个 \(u\) 所在连通块的权值之和为 \(m\)。可以做到 \(O(n^2V^2k^2)\),必死无疑。

这玩意儿是既加了状态又提前计算费用。

可以发现一起计算权值肯定需要一个 \(\sum V\),这玩意儿并不是很好记录,换一种思路,计算每个节点对答案的贡献。

所以理所当然设计一状态,\(dp[u][v][k]\) 表示 \(u\) 子树内有 \(k\) 个伐木场,且 \(u\) 的祖先中最深的伐木场在 \(v\)

然后这个就很好转移了。。。

复杂度 \(O(n^2k^2)\)

#include<cstdio>
typedef unsigned ui;
const ui M=105;
ui n,k,cnt,f[M],h[M],w[M],d[M],dp[M][M][55];
struct Edge{
	ui v,nx;
}e[M<<1];
inline void Add(const ui&u,const ui&v){
	e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
}
inline ui min(const ui&a,const ui&b){
	return a>b?b:a;
}
inline void DFS(const ui&u){
	for(ui x=u;~x;x=f[x])for(ui i=0;i<=k;++i)dp[u][x][i]=i?2e9:(d[u]-d[x])*w[u];
	for(ui E=h[u];E;E=e[E].nx){
		const ui&v=e[E].v;d[v]+=d[u];DFS(v);
		for(ui x=u;~x;x=f[x]){
			static ui tmp[M];for(int i=0;i<=k;++i)tmp[i]=2e9;
			for(ui i=0;i<=k;++i)for(ui j=0;j<=k;++j)if(i+j<=k)tmp[i+j]=min(tmp[i+j],dp[u][x][i]+dp[v][x][j]);
			for(ui i=0;i<=k;++i)dp[u][x][i]=tmp[i];
		}
	}
	for(ui x=f[u];~x;x=f[x])for(ui i=0;i<k;++i)dp[u][x][i+1]=min(dp[u][x][i+1],dp[u][u][i]);
}
signed main(){
	scanf("%u%u",&n,&k);for(ui i=1;i<=n;++i)scanf("%u%u%u",w+i,f+i,d+i),Add(f[i],i);
	f[0]=-1;DFS(0);printf("%u",dp[0][0][k]);
}
posted @ 2022-04-22 10:32  Prean  阅读(24)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};