题目描述

  公园里有$n$个雕像,有$n-1$条道路分别连接其中两个雕像,任意两个雕像可以直接或间接相连。现在每个景点$i$聚集着$P_i$只鸽子,旅行家手里有$v$数量的面包屑。
  一旦旅行家在雕像$i$撒下$1$单位面包屑,那么相邻的雕像的鸽子就都会飞到雕像$i$来觅食。
  时间线是这样的:首先,旅行家到达雕像$i$并与$P_i$鸽子会面。然后,他放下$1$单位面包屑。他离开雕像。在旅行家到达下一座雕像之前,来自相邻雕像的鸽子移动到雕像$i$(所以这些鸽子不计入他遇到的鸽子数)。注意旅行家每到一达雕像可以撒下面包屑,也可以不撒。
  旅行家可以在任何一座雕像上进入公园,沿着一些道路走下去(但不要使用同一道路两次),然后离开公园。
  在旅行家离开公园后,没有面包屑的小学生将进入并穿越完全相同的路线,并遇见许多群鸽子。
  通过最多$v$单位面包屑,旅行家希望最大化旅行家在路线上遇到的鸽子数量与小学生遇到的鸽子数量之间的差异。


输入格式

第一行两个整数$n,v$
第二行$n$个数为$P_i$
接下来$n-1$,每行两个整数,$X_i,Y_i$表示$X_i$与$Y_i$雕像相连


输出格式

输出只有一行,表示答案


样例

样例输入:

12 2
2 3 3 8 1 5 6 7 8 3 5 4
2 1
2 7
3 4  
4 7  
7 6  
5 6  
6 8  
6 9
7 10
10 11
10 12

样例输出:

36


数据范围与提示

样例解释:

一个可行的方案:旅行家从雕像$6$进入公园。在那里他遇到了$5$只鸽子。他放下面包屑。$p_6$现在是$27$,$p_5=p_7=p_8=p_9=0$。接下来,他跑向雕像$7$并遇到$0$鸽子。他撒下了第二个面包屑。$p_7=41$且$p_2=p_4=p_6=p_{10}=0$。他离开公园,他总共遇见$5+0=5$只鸽子。小学生跟着他走过同样的路线,但遇到$p_6+p_7=0+41=41$只鸽子。差是$41-5=36$。

数据范围:

对于$20\%$的数据,$1\leqslant n\leqslant 10$
对于另外$20\%$的数据,$1\leqslant n\leqslant 1,000$
对于另外$30\%$的数据,存在一个可行的最优方案从$1$出发
对于另外$30\%$的数据无特殊限制
对于$100\%$的数据,$1\leqslant n\leqslant 10^5,0\leqslant v\leqslant 100,0\leqslant P_i\leqslant 10^9$


题解

原题见$CEOI2017\ Chase$,我也不知道玄学出题人改的什么玄学题面……

一看就是$DP$题,但是显然我们不能枚举起点。

但是我们还是要先想一下枚举端点的做法,做事要慢慢来~

我的做法是设$dp[i][j][0/1]$表示到了$i$号点,已经撒了$j$次,在当前节点有没有撒的最大收益,转移是这样的:

$$dp[i][j][0]=max(dp[fa][j][0],dp[fa][j][1]) \\ dp[i][j][1]=max(dp[fa][j-1][0],dp[fa][j-1][1])+sum[i]-p[fa]$$

其中$sum[i]$表示在$i$号点撒会引来$sum[i]$只鸽子,不含$i$号点本身就有的,如下图$\downarrow$

$sum[i]$是指$\sum \limits_{i=1}^4 p_i$。

直接这样做会$TLE\ 44$,如果我们加上$clock()$的话可以得到$74\sim 78$不等。

那么我们现在考虑满分解法,如何快速求出以每个点为起点的最大贡献,将其取$\max$即可。

考虑定义两个数组$up[i][j]$和$down[i][j]$分别表示从$i$的子树走向$i$和从$i$走向$i$的子树,撒了$j$次的最大贡献。

然后状态转移是这样的:

$$up[i][j]=\max(up[i][j],up[son][j],up[son][j-1]+sum[i]-p[son]) \\ down[i][j]=\max(down[i][j],down[son][j],down[son][j-1]+sum[i]-p[fa])$$

还需要注意一点,如下图$\downarrow$

两种走法的最大贡献不一定相等,于是我们要正序枚举一遍所有的儿子,再倒着枚举一遍即可。

时间复杂度:$\Theta(n\times v)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,v;
int p[100001];
long long sum[100001];
long long dp[2][100001][101];
long long ans;
vector<int> e[100001];
void dfs(int x,int fa)
{
for(int i=1;i<=v;i++)
{
dp[0][x][i]=sum[x];
dp[1][x][i]=sum[x]-p[fa];
}
for(int i=0;i<e[x].size();i++)
if(e[x][i]!=fa)
{
dfs(e[x][i],x);
for(int j=1;j<v;j++)ans=max(ans,dp[0][x][j]+dp[1][e[x][i]][v-j]);
for(int j=1;j<=v;j++)
{
dp[0][x][j]=max(dp[0][x][j],max(dp[0][e[x][i]][j],dp[0][e[x][i]][j-1]+sum[x]-p[e[x][i]]));
dp[1][x][j]=max(dp[1][x][j],max(dp[1][e[x][i]][j],dp[1][e[x][i]][j-1]+sum[x]-p[fa]));
}
}
reverse(e[x].begin(),e[x].end());
for(int i=1;i<=v;i++)
{
dp[0][x][i]=sum[x];
dp[1][x][i]=sum[x]-p[fa];
}
for(int i=0;i<e[x].size();i++)
if(e[x][i]!=fa)
{
for(int j=1;j<v;j++)ans=max(ans,dp[0][x][j]+dp[1][e[x][i]][v-j]);
for(int j=1;j<=v;j++)
{
dp[0][x][j]=max(dp[0][x][j],max(dp[0][e[x][i]][j],dp[0][e[x][i]][j-1]+sum[x]-p[e[x][i]]));
dp[1][x][j]=max(dp[1][x][j],max(dp[1][e[x][i]][j],dp[1][e[x][i]][j-1]+sum[x]-p[fa]));
}
}
ans=max(ans,max(dp[0][x][v],dp[1][x][v]));
}
int main()
{
scanf("%d%d",&n,&v);if(!v){puts("0");return 0;}
for(int i=1;i<=n;i++)scanf("%d",&p[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
sum[x]+=p[y];
sum[y]+=p[x];
}
dfs(1,0);
printf("%lld",ans);
return 0;
}

rp++

[CSP-S模拟测试]:Park(树上DP)的更多相关文章

  1. [CSP-S模拟测试]:B(DP+数学)

    题目传送门(内部题45) 输入格式 第一行$3$个整数$n,m,P$.第二行$m$个整数,表示$m$次询问. 输出格式 一行$m$个整数表示答案. 样例 样例输入1: 2 4 40 1 2 3 样例输 ...

  2. [CSP-S模拟测试]:蛇(DP+构造+哈希)

    题目传送门(内部题140) 输入格式 前两行有两个长度相同的字符串,描述林先森花园上的字母. 第三行一个字符串$S$. 输出格式 输出一行一个整数,表示有多少种可能的蛇,对$10^9+7$取模. 样例 ...

  3. [CSP-S模拟测试]:最小值(DP+乱搞)

    题目背景 $Maxtir$更喜欢序列的最小值. 题目传送门(内部题128) 输入格式 第一行输入一个正整数$n$和四个整数$A,B,C,D$. 第二行输入$n$个整数,第$i$个数表示$a_i$. 输 ...

  4. [CSP-S模拟测试]:花(DP)

    题目传送门(内部题111) 输入格式 一个整数$T$,表示测试数据组数. 每组测试数据占一行,两个整数,分别表示$L$和$S$. 输出格式 对每组数据,输出一个整数表示答案. 样例 样例输入1: 13 ...

  5. [CSP-S模拟测试]:计数(DP+记忆化搜索)

    题目描述 既然是萌萌哒$visit\text{_}world$的比赛,那必然会有一道计数题啦!考虑一个$N$个节点的二叉树,它的节点被标上了$1\sim N$的编号.并且,编号为$i$的节点在二叉树的 ...

  6. [CSP-S模拟测试]:matrix(DP)

    题目描述 求出满足以下条件的$n\times m$的$01$矩阵个数:(1)第$i$行第$1~l_i$列恰好有$1$个$1$.(2)第$i$行第$r_i~m$列恰好有$1$个$1$.(3)每列至多有$ ...

  7. [CSP-S模拟测试]:题(DP+数学)

    题目描述 出个题就好了.这就是出题人没有写题目背景的原因.你在平面直角坐标系上.你一开始位于$(0,0)$.每次可以在上/下/左/右四个方向中选一个走一步.即:从$(x,y)$走到$(x,y+1),( ...

  8. [CSP-S模拟测试]:题(DP)

    题目描述 由于出题人赶时间所以没办法编故事来作为背景.一开始有$n$个苹果,$m$个人依次来吃苹果,第$i$个人会尝试吃$u_i$或$v_i$号苹果,具体来说分三种情况.$\bullet 1.$两个苹 ...

  9. [CSP-S模拟测试]:y(DP+bitset)

    题目背景 $\frac{1}{4}$遇到了一道水题,叕完全不会做,于是去请教小$D$.小$D$懒得理$\frac{1}{4}$,直接就离开了.于是,$\frac{1}{4}$只好来问你,这道题是这样的 ...

随机推荐

  1. Spring Boot 之 RabbitMQ 消息队列中间件的三种模式

    开门见山(文末附有消息队列的几个基本概念) 1.直接模式( Direct)模式 直白的说就是一对一,生产者对应唯一的消费者(当然同一个消费者可以开启多个服务). 虽然使用了自带的交换器(Exchang ...

  2. Java -Tips

    1. /* xxxx */表示多行注释,双斜杠开始表示单行注释.多行注释的快捷键: 先选中多行代码,然后按下ctrl+/就可以把选中的多行代码给注释掉.

  3. [2019杭电多校第十场][hdu6701]Make Rounddog Happy

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6701 题目大意为求满足 $max(a_{l},a_{l+1}\cdot \cdot \cdot a_{ ...

  4. django 开发中数据库做过什么优化??

    1.设计表时,尽量少使用外键,因为外键约束会影响插入和删除性能: 2.使用缓存,减少对数据库的访问: 3.在 orm 框架下设置表时,能用 varchar 确定字段长度时,就别用 text: 4.可以 ...

  5. svn登录问题

    转载自: https://www.cnblogs.com/WQX-work24/p/9790260.html 版权归该作者所有.

  6. spark复习笔记(3)

    在windows上实现wordcount单词统计 一.编写scala程序,引入spark类库,完成wordcount 1.sparkcontextAPI sparkcontext是spark功能的主要 ...

  7. 菜鸟程序员成长史 --记 Github 1000+ contributions

    其实一直以来想写一篇文章总结这几年的技术学习,刚好趁着自己的第一次github contribution 达到1000+,写篇文章总结以下.本文篇幅较长,我会分为几个章节来分别阐述. 博客篇 为什么我 ...

  8. Docker备份与迁移

    容器保存为镜像 通过以下命令将容器保存为镜像: docker commit [-m="提交的描述信息"] [-a="创建者"] 容器名称|容器ID 生成的镜像名 ...

  9. Apache Mesos 官方文档 V1.0

    Apache Mesos 官方文档 V1.0 2016-11-07 中文版:http://mesos.mydoc.io/ gitBook :https://www.gitbook.com/book/m ...

  10. Rsync+sersync 数据同步指南

    (1):sersync 可以记录下被监听目录中发生变化的(包括增加.删除.修改)具体某一个文件或 某一个目录的名字: (2):rsync 在同步的时候,只同步发生变化的这个文件或者这个目录(每次发生变 ...