这是一道...卡了我一个月的树形dp...

我真是太弱了...

其实仔细想想,这题的核心思路并不是特别复杂,但是的确存在不小的难度

作为一个看过全网基本所有题解+标程才弄明白这题到底怎么回事的蒟蒻,我努力把所有东西揉到一起让各位看官一眼看懂...

首先我们简化一下题意:给定一棵满二叉树,每个叶节点有一个状态(0,1),任选两个叶节点,如果这两个叶节点状态相同但他们的LCA所管辖的子树中的与他们状态相同的叶节点个数较少(少于1/2),则会产生2f的代价,如果状态不同,则产生f的代价,如果状态相同且LCA管辖子树中与他们状态相同叶节点个数较多,则不产生代价,现在每个节点可以变更状态,但变更状态也有自己的代价,求最小总代价

那么..怎么搞?

首先,有一个很重要的思想:点对之间的问题是难以快速解决的!

很简单,因为如果我们按点对统计贡献,那么在枚举到每个叶节点都需要考虑其他所有叶节点,这样是不利于我们处理问题的

所以我们第一步要考虑的是把点对的贡献压到一个点上

很幸运,题目给出了这样的方式:

注意题目中“产生2f的代价”“产生f的代价”这两句话!

那么如果我们同样给所有非叶节点一个状态(0,1),代表这个节点管辖的子树中叶节点状态为0的多还是状态为1的多,那么我们显然可以看到:如果一个叶节点和这个根节点的状态相同,那么这个叶节点不会产生贡献,反之会产生一个f的贡献!

证明:分类讨论:

①:假设两个节点与根节点状态都相同,那么这两个节点都不产生贡献,满足题意

②:假设两个节点与根节点状态都不同,那么这两个节点都产生一个f的贡献,满足题意

③:如果有一个点与根节点状态相同,那么这两个节点只产生一个f的贡献,同样满足题意

因此我们这样处理点对是正确的

总结:在处理点对时,我们要把一个点对的贡献压到一个点上,同时给所有非叶节点一个状态,这样就能满足题意了

接下来就可以进行树形dp了

记状态dp[i][j]表示当前位于树上的第i个节点,其子树的叶节点中状态为0的点的个数为j时所需的最小代价

(这里对题意有一个小提示:当两种状态的叶节点数量相等时,认为状态为0的叶节点个数多)

如果这个节点不是叶节点,那么显然,这个节点会有两种可能的状态:

①:这个节点状态为1,认为对应的情况为子树中状态为0的节点偏多,那么可以转移的dp部分是叶节点个数/2-叶节点个数

②:这个节点状态为0,认为对应的情况为子树中状态为1的节点偏多,那么可以转移的dp部分是0-叶节点个数/2-1

那么我们分两类dfs处理,对每类情况分别合并即可

如果这个节点是叶节点,那么我们反过来枚举他上面一条链的情况,然后统计代价即可,一定注意dp的第二维代表状态为0的节点的数目!

在统计代价的时候,我们还涉及一个小问题,就是如果每次找到根节点时都枚举所有点计算代价,时间承受不了,所以我们对代价求前缀和,然后用类似倍增的方法计算总代价即可。

当然,我们不可能一直枚举上面一条链的情况,所以我们直接把这条链的状态状压,传进dfs里即可,这样也就不涉及网上大部分题解都涉及到的压缩空间的问题了。

提示:这是一棵满二叉树,所以可以用类似线段树的方式去遍历。

这样这道题就结束了

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define rt1 rt<<1
#define rt2 (rt<<1)|1
using namespace std;
int dp[(<<)+][(<<)+];
int v[(<<)+][(<<)+];
int cv[(<<)+];
int ori[(<<)+];
int temp[(<<)+];
int lq[],rq[];
int n;
void dfs(int rt,int l,int r,int sit,int dep)
{
if(l==r)
{
dep--;
dp[rt][]=dp[rt][]=;
if(ori[l])
{
dp[rt][]=cv[l];
}else
{
dp[rt][]=cv[l];
}
for(int i=;i<=dep;i++)
{
int mid=(lq[i]+rq[i])>>;
if((sit&(<<(dep-i))))
{
if(l<=mid)
{
dp[rt][]+=v[l][rq[i]]-v[l][mid];
}else
{
dp[rt][]+=v[l][mid]-v[l][lq[i]-];
}
}else
{
if(l<=mid)
{
dp[rt][]+=v[l][rq[i]]-v[l][mid];
}else
{
dp[rt][]+=v[l][mid]-v[l][lq[i]-];
}
}
}
return;
}
int mid=(l+r)>>;
int len=r-l+;
lq[dep]=l;
rq[dep]=r;
dfs(rt1,l,mid,(sit<<),dep+);
dfs(rt2,mid+,r,(sit<<),dep+);
memset(temp,0x3f,sizeof(temp));
for(int i=;i<=len/-;i++)
{
for(int j=;j<=i;j++)
{
temp[i]=min(temp[i],dp[rt1][j]+dp[rt2][i-j]);
}
}
for(int i=;i<=len/-;i++)
{
dp[rt][i]=temp[i];
}
dfs(rt1,l,mid,(sit<<)|,dep+);
dfs(rt2,mid+,r,(sit<<)|,dep+);
memset(temp,0x3f,sizeof(temp));
for(int i=len/;i<=len;i++)
{
for(int j=;j<=i;j++)
{
temp[i]=min(temp[i],dp[rt1][j]+dp[rt2][i-j]);
}
}
for(int i=len/;i<=len;i++)
{
dp[rt][i]=temp[i];
}
}
int main()
{
scanf("%d",&n);
n=(<<n);
for(int i=;i<=n;i++)
{
scanf("%d",&ori[i]);
}
for(int i=;i<=n;i++)
{
scanf("%d",&cv[i]);
}
for(int i=;i<=n;i++)
{
for(int j=i+;j<=n;j++)
{
scanf("%d",&v[i][j]);
v[j][i]=v[i][j];
}
}
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
v[i][j]=v[i][j-]+v[i][j];
}
}
memset(dp,0x3f,sizeof(dp));
dfs(,,n,,);
int ans=;
for(int i=;i<=n;i++)
{
ans=min(ans,dp[][i]);
}
printf("%d\n",ans);
return ;
}

bzoj 1495的更多相关文章

  1. BZOJ 1495 [NOI2006]网络收费(暴力DP)

    题意 给定一棵满二叉树,每个叶节点有一个状态0/10/10/1,对于每两个叶节点i,ji,ji,j,如果这两个叶节点状态相同但他们的LCALCALCA所管辖的子树中的与他们状态相同的叶节点个数较少(少 ...

  2. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

  3. BZOJ 3144: [Hnoi2013]切糕

    3144: [Hnoi2013]切糕 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1495  Solved: 819[Submit][Status] ...

  4. BZOJ 3275: Number

    3275: Number Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 874  Solved: 371[Submit][Status][Discus ...

  5. BZOJ 2879: [Noi2012]美食节

    2879: [Noi2012]美食节 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1834  Solved: 969[Submit][Status] ...

  6. bzoj 4610 Ceiling Functi

    bzoj 4610 Ceiling Functi Description bzoj上的描述有问题 给出\(n\)个长度为\(k\)的数列,将每个数列构成一个二叉搜索树,问有多少颗形态不同的树. Inp ...

  7. BZOJ 题目整理

    bzoj 500题纪念 总结一发题目吧,挑几道题整理一下,(方便拖板子) 1039:每条线段与前一条线段之间的长度的比例和夹角不会因平移.旋转.放缩而改变,所以将每条轨迹改为比例和夹角的序列,复制一份 ...

  8. 【sdoi2013】森林 BZOJ 3123

    Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负整数 ...

  9. 【清华集训】楼房重建 BZOJ 2957

    Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...

随机推荐

  1. python - one day

    1. python历史. 2008 年出现 python 2.7 与 python 3.0 两个版本,后来 吉多·范罗苏姆 大叔决定停用 python 2.7,但因用户反对,于是决定于 2020 年停 ...

  2. rpmlib(PayloadIsLzma) <= 4.4.6-1 is needed【转载】

    以下为转载,但是有改动,原作者在一处写错了,将高写成了低,直接差之毫厘,谬之千里. 环境: centos el5 背景: 由于个人比较喜欢用软件的最新版本,在重新安装服务器上的 xdg-open(还有 ...

  3. Log4Net配置日志

    1.log4net 1)新建一个Net空白项目,在引用出点击管理NuGet程序包,搜索log4net并安装 2)建立log4net.config配置文件 在configuration里面添加如下代码, ...

  4. mongodb 案例 ~ 经典故障案例

    一 简介:此文汇总遇到过和搜集过的故障案例 二 场景案例 1 问题描述: mongo集群在无任何业务情况下,mongos所在服务器cpu突然被打满,内核日志报错 mongos被hung住,非常奇怪的问 ...

  5. mysql案例~关于linux服务器本身的优化问题

    简介:mysql服务优化分为 1服务器本身的优化 2mysql本身的性能优化 今天咱们来讨论下服务器本身的优化性能 一 参数的优化简介 1 文件系统的选择 Linux 常用文件系统: ext3, ex ...

  6. Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields(翻译)

    0 - Abstract 我们提出了一种方法去在一张图片中有效地识别多个人体的2D姿势.这个方法使用了一个无参数表示法,我们将其叫为Part Affinity Fields(PAFs),其是去在图片中 ...

  7. 20165237 2017-2018-2 《Java程序设计》第2周学习总结

    20165237 2017-2018-2 <Java程序设计>第2周学习总结 教材学习内容总结 1.标识符第一个字符不能是数字. 2.标识符不能是关键字,也不能是true.false和nu ...

  8. 20165221 JAVA第二周学习心得及体会

    基本数据类型与数组理论学习 根据第二章的网课链接,归纳出以下板块: 知识框架 标识符与关键字 1.标识符 其本质是文件名字 标识符的第一个字符不能为数字,标识符不能为关键字(如inter) 标识符不能 ...

  9. html5离线记事本

    离线记事本 这是一个笔记应用,不需要联网,也不需要数据库,可以直接把数据储存在本地.方便易用! ^_^ <!DOCTYPE html>  <html>  <head> ...

  10. Mongoose简介

    Mongoose 官网地址:http://mongoosejs.com/   ,Mongoose 为node.js提供了优雅的,针对mongodb的ODM(Object Document Mappin ...