CF1988D The Omnipotent Monster Killer
CF1988D The Omnipotent Monster Killer
本文同步于我的网站。
Problem
怪物们在一棵有 个顶点的树上,编号为 的怪物位于编号为 的顶点上,攻击力为 。你需要与怪物战斗 个回合。在每个回合中,会依次发生以下两步:
- 所有活着的怪物攻击你。你的生命值会按照所有活体怪物攻击点的总和减少。
- 您选择一些(可以选全部,也可以不选)怪物并杀死它们。被杀死的怪物将不会再进行攻击。
限制条件:在一个回合内不能杀死相邻的两只怪物。
如果您以最佳选择方式攻击的怪物,那么在所有回合后,您的健康值减少的最小值是多少?
Solution
这是一道再经典不过的树形DP了。太惭愧了。
每个节点的贡献可以表示为 的形式,其中 表示怪物 是第 次被杀死的。可以证明 不会超过 。
图:Taibo
上图中,欲构造出 的点,需要将该点连接上 的节点。设构造出 的树至少需要 个节点,则存在
即得 。也就是说对于一张 个节点的图,其至多需要 次选择就可以将所有怪物杀死。
下面开始dp。设 表示若第 次杀死怪物 , 子树内的怪物至少会产生多少点伤害。
由两部分组成:
- 在第 次杀死怪物 之前,怪物 会产生 点伤害。
- 的子树内的怪物(除了 本身)产生的伤害。
其中 表示点 的儿子节点。
最后答案为
Code
#define N 300010
int n;
int head[N],nxt[N*2],ver[N*2],cnt;
void insert(int x,int y)
{
nxt[++cnt]=head[x];
head[x]=cnt;
ver[cnt]=y;
}
LL a[N];
#define K 25
#define inf (1ll<<62)
LL dp[N][K+5];
void dfs(int x,int f)
{
for(int i=1;i<=K;i++)
{
dp[x][i]=a[x]*i;
}
for(int i=head[x];i;i=nxt[i])
{
int y=ver[i];
if(y==f) continue;
dfs(y,x);
for(int j=1;j<=K;j++)//点x将被第j次选
{
LL mn=inf;
for(int k=1;k<=K;k++)//相邻点y将被第k次选
{
if(j!=k)
{
mn=min(mn,dp[y][k]);
}
}
dp[x][j]+=mn;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<n;i++)
{
int x,y;cin>>x>>y;
insert(x,y);
insert(y,x);
}
dfs(1,0);
LL ans=inf;
for(int i=1;i<=K;i++)
{
ans=min(ans,dp[1][i]);
}
cout<<ans<<endl;
for(int i=1;i<=cnt;i++)
{
head[i]=nxt[i]=ver[i]=0;
}
cnt=0;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2019-07-16 洛谷P1091 合唱队形
2019-07-16 洛谷P1004 方格取数 NOIP 2000 提高组第四题
2019-07-16 洛谷P1067 多项式输出 NOIP 2009 普及组 第一题
2019-07-16 嵊州D6T2 城市 city
2019-07-16 博弈论小结