一道有机结合了计数贪心这一DP两大考点的神仙题,不得不说做法是很玄妙。

首先我们很容易想到DP,设\(f_{i,j}\)表示在以\(i\)为根节点的子树中选\(j\)个黑色节点的最大收益值。

然后我们考虑那种暴力转移就是那种看上去是\(O(n^3)\)实际经严格证明后时\(O(n^2)\)的DP

然后推推推推推推,一个小时过去还是一个屁

这个时候我们不禁质疑,这个鬼状态不会是错的吧。

没错,它就是错的,因为这样对于你子树上面的黑点节点之间的收益你都一无所知

然后我们联想到另外一道树上计数的题目:51Nod 1677 treecnt&&sol,然后我们又是单独考虑每一条边的贡献

再仔细推一波可以发现一条边对于黑白点的贡献之和两边黑白点的个数有关,和具体的结构鸟关系都没有。

于是我们换一波方程,设\(f_{i,j}\)表示在以\(i\)为根节点的子树中选\(j\)个黑色节点对总答案的贡献

然后我们枚举子树中黑色点的数量然后一个类似于背包的转移即可。

具体看CODE

#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
const int N=2005;
struct edge
{
int to,next,v;
}e[N<<1];
int head[N],size[N],n,k,cnt,x,y,z,rt=1;
long long f[N][N];
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void double_add(int x,int y,int z)
{
e[++cnt].to=y; e[cnt].next=head[x]; e[cnt].v=z; head[x]=cnt;
e[++cnt].to=x; e[cnt].next=head[y]; e[cnt].v=z; head[y]=cnt;
}
inline void maxer(long long &x,long long y)
{
if (y>x) x=y;
}
inline int min(int a,int b)
{
return a<b?a:b;
}
inline void DFS(int now,int fa)
{
register int i,j,s,x; size[now]=1;
f[now][0]=f[now][1]=0;
for (i=head[now];~i;i=e[i].next)
if (e[i].to!=fa) DFS(e[i].to,now),size[now]+=size[e[i].to];
for (i=head[now];~i;i=e[i].next)
if (e[i].to!=fa) for (j=min(k,size[now]);j>=0;--j)
{
for (s=0,x=min(j,size[e[i].to]);s<=x;++s)
maxer(f[now][j],f[e[i].to][s]+f[now][j-s]+1LL*e[i].v*(1LL*s*(k-s)+1LL*(size[e[i].to]-s)*(n-k-size[e[i].to]+s)));
}
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i; read(n); read(k);
if (2*k>n) k=n-k;
memset(head,-1,sizeof(head)); memset(f,167,sizeof(f));
for (i=1;i<n;++i)
read(x),read(y),read(z),double_add(x,y,z);
DFS(rt,-1); return printf("%lld",f[rt][k]),0;
}

注意上面的一个小trick

if (2*k>n) k=n-k;

这样对无关的常数浪费就会大大降低直接帮助我卡过了BZOJ的老爷机,不加T死

Luogu P3177 [HAOI2015]树上染色的更多相关文章

  1. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

  2. P3177 [HAOI2015]树上染色

    题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之 ...

  3. 洛谷 P3177 [HAOI2015]树上染色

    题目链接 题目描述 有一棵点数为 \(N\) 的树,树边有边权.给你一个在 \(0~ N\) 之内的正整数 \(K\) ,你要在这棵树中选择 \(K\)个点,将其染成黑色,并将其他 的\(N-K\)个 ...

  4. 【洛谷】P3177 [HAOI2015]树上染色

    懒得复制题面了直接传送门吧 分析 直接求点与点之间的距离感觉不是很好求,所以我们考虑换一个求法. 瞄了一眼题解 距离跟路径上边的长度有关,所以我们直接来看每一条边的贡献吧(这谁想得到啊) 对于每一条边 ...

  5. 洛谷P3177 [HAOI2015]树上染色(树形dp)

    题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之 ...

  6. 洛谷P3177 [HAOI2015]树上染色(树上背包)

    题意 题目链接 Sol 比较套路吧,设\(f[i][j]\)表示以\(i\)为根的子树中选了\(j\)个黑点对答案的贡献 然后考虑每条边的贡献,边的两边的答案都是可以算出来的 转移的时候背包一下. # ...

  7. BZOJ 4033: [HAOI2015]树上染色题解

    BZOJ 4033: [HAOI2015]树上染色题解(树形dp) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327400 原题地址: BZOJ 403 ...

  8. bzoj 4033: [HAOI2015]树上染色 [树形DP]

    4033: [HAOI2015]树上染色 我写的可是\(O(n^2)\)的树形背包! 注意j倒着枚举,而k要正着枚举,因为k可能从0开始,会使用自己更新一次 #include <iostream ...

  9. BZOJ4033: [HAOI2015]树上染色(树形DP)

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3461  Solved: 1473[Submit][Stat ...

随机推荐

  1. Linux 操作系统下为网卡配置ip

    Linux操作系统下为网卡配置ip by:授客 QQ:1033553122 1.   Linux单一网卡设置多IP的配置方法 在Linux下网卡接口逻辑名被称为eth0,eth1,eth2,..... ...

  2. long数值 转换为时间

    项目中,服务器端经常给客户端开发人员传一个长整形的时间数据, 对于一个 长整形 1446801883000,可以明显的看出 是以毫秒为单位的,因为最后有三个零,如果没有连续3个零的话就要判断单位了 那 ...

  3. (网页)jQuery UI 实例 - 日期选择器(Datepicker)

    默认功能 日期选择器(Datepicker)绑定到一个标准的表单 input 字段上.把焦点移到 input 上(点击或者使用 tab 键),在一个小的覆盖层上打开一个交互日历.选择一个日期,点击页面 ...

  4. Spark程序数据结构优化

    场景: 1.scala中的对象:对象头是16个字节(包含指向对象的指针等源数据信息),如果对象中只有一个int的属性,则会占用20个字节,也就是说对象的源数据占用了大部分的空间,所以在封装数据的时候尽 ...

  5. sleep和Sleep区别

    windows Sleep 单位是毫秒 linux sleep 单位是秒

  6. STL set简单用法

    set的常见用法详解 set翻译为集合,是一个内部自动有序并且不含重复元素的容器. 可以用于去掉重复元素,或者元素过大,或者不能散列的情况,set只保留元素本身而不考虑它的个数. 头文件:#inclu ...

  7. Linux 内存使用率

    文章参考: 1.正确计算linux系统内存使用率 2.Linux系统内存消失与slab使用之谜 例如当前主机内存信息如下: [zhang@test ~]$ cat /proc/meminfo MemT ...

  8. JavaScript中数组的增删改查以及应用方式

    数组的增加方法 1.push()方法向数组中末尾添加一个元素,原数组改变 var arr=[1,2,3,4]; var arr1=arr.push(6); console.log(arr);//打印出 ...

  9. Java输出打印工具类封装

    在进行Java打印输出,进行查看字段值的时候,觉得每次写了System.out.println之后,正式发布的时候,还得一个个的删掉,太麻烦了,经过别人的指教,做了一个Java的打印输出封装类,只为记 ...

  10. Django之Template

    模板层(template) 概念:  模板与html的区别:  模板=html+模板语法 模板语法: 1 变量:       {{}}    深度查询: 通过句点符.    列表,字典    clas ...