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]);
}