【2020NOI.AC省选模拟#6】A. zyb的监控计划

题目链接

原题解:

考虑我们需要的信息:子树里最浅的一个能向上的点是谁?子树里最深的一个没被覆盖的深度是多少?

我们记录一下fi,a,b表示上面两个信息为ab的时候,最少要花费的代价。

转移的时候枚举c,d进行转移,看起来就很麻烦。

然后我们注意一个结论:考虑如果ab的话,这个b其实是0,而如果a<b的话,证明之后存在一个节点x,到i之后剩余能覆盖的距离至少是b,所以ab中一定有一个信息是没用的。

我们令fi,a表示存在一个还能覆盖是a的点,gi,b表示存在一个深度为b的还没覆盖的点。

考虑暴力转移,可以通过前缀和优化直接做到O(NK)

补充:

从找到“有用信息”这一步我就被拒之门外了。。。

然后“有用信息”之间也是有相互影响的关系的。搞清楚本质有助于优化DP。

 

代码(100分):

复制代码
#include<cstdio>
#include<cstring>
#define K 202
#define M 200002
#define N 100001
inline int min(int x,int y){return x<y?x:y;}
int a[N],b[M],c[M],e[N],f[N][K],g[K],m,n;
void dfs(int u,int v)
{
    for(int i=0;i<=m;i++)f[u][i]=1000000000;
    for(int&i=a[u];i;i=b[i])if(c[i]!=v)
    {
        dfs(c[i],u);
        for(int j=0;j<m;j++)g[j+1]=min(g[j+1],f[c[i]][j]+f[u][m+m-j]);
        for(int j=m;j<=m<<1;j++)g[m+m-j]=min(g[m+m-j],f[c[i]][j]+f[u][m+m-j]);
        for(int j=m;j<=m<<1;j++)g[j+1]=f[c[i]][j]+f[u][j+1];
        for(int j=1;j<=(m<<1|1);j++)f[u][j]=min(f[u][j-1],g[j]),g[j]=1000000000;
    }
    for(int i=0;f[u][m<<1|1]+e[u]<f[u][i];i++)f[u][i]=f[u][m<<1|1]+e[u];
}
int i,u,v;
int main()
{
    for(scanf("%d%d",&n,&m),i=1;i<=(m<<1|1);i++)g[i]=1000000000;
    for(i=1;i<=n;i++)scanf("%d",e+i);
    for(i=1;i<n;i++)scanf("%d%d",&u,&v),b[i<<1]=a[u],c[a[u]=i<<1]=v,b[i<<1|1]=a[v],c[a[v]=i<<1|1]=u;
    return 0&(dfs(1,0),printf("%d\n",f[1][m]));
}
View Code
复制代码

 

posted @   汉谡  阅读(190)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 上周热点回顾(1.20-1.26)
· 【译】.NET 升级助手现在支持升级到集中式包管理
点击右上角即可分享
微信分享提示