这类题目是真的很头疼....其实这类题目的特征也很明显,叶子结点贡献答案时和其所在链的祖宗有关,也就是说要想得知其贡献必须知道他的所有祖宗的贡献,其实处理方法也不是太难,就是在dfs枚举时顺便把祖宗的状态状压一下.

到叶子结点时统计答案,最后将答案上传就行了.

战争调度

这个算是这类题目最好的例题了.很显然,一个平民的贡献只和他的直系上属有关转化为图论的语言就是和他的所有祖宗有关.而非叶结点又不会贡献答案.

我们直接给每个非叶结点一个状态0/1表示其参与战争还是后勤,我们在dfs传参数时直接记录下所有的祖宗信息就行了.这样到叶子结点后,我们就能很轻松的统计答案了.

同时由于不超过m个人参与战争的限制,我们设dp[x][i]表示点x控制的平民在中有i个人参与战争的最大贡献,直接转移就行了.

//不等,不问,不犹豫,不回头.
//这类题真的好难搞啊.....
//首先要想统计一个子节点的贡献,必须知道他所有祖宗的状态,所以就有了这种做法,在dfs时一遍枚举
//当前结点的贡献一遍往下递归.这样当到最底层时,其所有祖宗的状态就已经知道了,其叶节点的贡献也就
//容易知道了.回溯时再向父结点转移.
#include<bits/stdc++.h>
#define _ 0
#define db double
#define RE register
#define ll long long
#define P 1000000007
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define pb(x) push_back(x)
#define ull unsigned long long
#define getc(c) scanf("%s",c+1)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(i,x,y) for(RE int i=x;i<=y;++i)
#define fep(i,x,y) for(RE int i=x;i>=y;--i)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=2500;
int n,m,w[N][15],f[N][15],num,dp[N][N]; inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
} inline void dfs(int x,int s,int sz)//1打仗,0后勤.
{
rep(i,0,sz) dp[x][i]=0;
if(sz==1)
{
rep(i,0,n-2) if(!(s&1<<i)) dp[x][0]+=f[x][i+1];
rep(i,0,n-2) if(s&1<<i) dp[x][1]+=w[x][i+1];
return;
}
rep(k,0,1)
{
dfs(x<<1,s<<1|k,sz>>1);dfs(x<<1|1,s<<1|k,sz>>1);
rep(i,0|k,min(sz,m)) rep(j,0,i)
dp[x][i]=max(dp[x][i],dp[x<<1][j]+dp[x<<1|1][i-j]);
}
} int main()
{
//freopen("1.in","r",stdin);
get(n);get(m);num=1<<n-1;
rep(i,num,num*2-1) rep(j,1,n-1) get(w[i][j]);
rep(i,num,num*2-1) rep(j,1,n-1) get(f[i][j]);
dfs(1,0,(1<<n)-1);
int ans=0;
rep(i,0,m) ans=max(ans,dp[1][i]);
put(ans);
return (0^_^0);
}
//以吾之血,祭吾最后的亡魂

网络收费

这个真的算是秒题了,算是我写的第二道黑题吧!(虽然是照着题解一个字母一个字母抄的....)

首先我们要解决点对对答案的贡献,我们总不能在处理一个点时还知道其他点的状态吧!那样必然会很麻烦!

题目中的收费标准归纳一下就是:如果两个点对不同的话,代价为一个f,点对相同且为lca数量多的模式,则无代价.为lca数量少的模式贡献两个f.

这启示我们将点的贡献放到其lca上,且标记点那种模式较多,如果一个点模式与lca的模式不同,必然会造成一个f的代价!容易发现这和题意的限制相对应.

这样我们只需要一个一个统计点的贡献即可.之后就转换成和上一道题类似的模型.只不过细节更加繁琐......

//不等,不问,不犹豫,不回头.
//观察这道网络收费的题,如果我们将贡献放到非叶子节点上的话,进行dp就比较合理了
//首先观察题意可以归纳出以下结论:若两个叶结点不同,必然贡献f[i][j]的贡献,相同的话若状态为lca
//的多数叶子结点的状态的话,则无贡献.否则贡献为2*f[i][j].
//首先要解决的问题便是点对之间的贡献如何处理.因为这个限制我们在处理一个点时,必须考虑其他点
//的影响,这使得求解起来非常麻烦.考虑将两个点对的贡献放到其lca处.我们额外给非叶子结点状态0/1
//表示其子树内哪个状态比较多,0表示子树内1偏多,1表示子树内0偏多,如果一个叶子结点与其状态不同
//必然付出f的代价.否则无代价.发现这和题目的限制是相应的.之前一直不理解这个意思,现在恍然大悟.
//当状态不同时,他要累加上其他所有点的代价,因为不管另一个点是什么,他已经会造成1的代价了.
//至于另一个如果也造成代价的话,我们枚举另一个点时会计算上的.
//之后发现一个点的贡献与其所有的祖宗结点相关,和战争调度类似在dfs时直接带上祖宗的状态即可.
#include<bits/stdc++.h>
#define _ 0
#define db double
#define RE register
#define ll long long
#define P 1000000007
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define pb(x) push_back(x)
#define ull unsigned long long
#define getc(c) scanf("%s",c+1)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(i,x,y) for(RE int i=x;i<=y;++i)
#define fep(i,x,y) for(RE int i=x;i>=y;--i)
#define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=(1<<11)+10;
int dp[N][N],v[N][N],n,ori[N],cv[N],lq[N],rq[N]; inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
} inline void dfs(int x,int l,int r,int s,int dep)
{
rep(i,0,r-l+1) dp[x][i]=INF;
if(l==r)
{
dep--;
dp[x][0]=dp[x][1]=0;
if(ori[l]) dp[x][1]=cv[l];//注意这里1指的是0的状态比1多,所以此时其实上x的状态为0.
else dp[x][0]=cv[l];
rep(i,1,dep)
{
int mid=(lq[i]+rq[i])>>1;
if(s&1<<dep-i)
{
if(l<=mid) dp[x][0]+=v[l][rq[i]]-v[l][mid];
else dp[x][0]+=v[l][mid]-v[l][lq[i]-1];
}
else
{
if(l<=mid) dp[x][1]+=v[l][rq[i]]-v[l][mid];
else dp[x][1]+=v[l][mid]-v[l][lq[i]-1];
}
}
return;
}
int mid=l+r>>1;
int len=r-l+1;
lq[dep]=l;rq[dep]=r;
dfs(x<<1,l,mid,s<<1,dep+1);
dfs(x<<1|1,mid+1,r,s<<1,dep+1);
rep(i,0,len/2-1) rep(j,0,i) dp[x][i]=min(dp[x][i],dp[x<<1][j]+dp[x<<1|1][i-j]);
//注意这里0的个数只能限制为0 - len/2-1.因为我们这里的0状态实际上是文中的模式A.
//而上面我们已经强制让这个点选了状态0,说明此时1的状态多余0的状态,所以0的数量只能不足一半.
dfs(x<<1,l,mid,s<<1|1,dep+1);
dfs(x<<1|1,mid+1,r,s<<1|1,dep+1);
rep(i,len/2,len) rep(j,0,i) dp[x][i]=min(dp[x][i],dp[x<<1][j]+dp[x<<1|1][i-j]);
} int main()
{
//freopen("1.in","r",stdin);
get(n);n=1<<n;//所有的叶子结点个数.
rep(i,1,n) get(ori[i]);
rep(i,1,n) get(cv[i]);
rep(i,1,n-1) rep(j,i+1,n) get(v[i][j]),v[j][i]=v[i][j];
rep(i,1,n) rep(j,1,n) v[i][j]+=v[i][j-1];
memset(dp,0x3f,sizeof(dp));
dfs(1,1,n,0,1);
int ans=INT_MAX;
rep(i,0,n) ans=min(ans,dp[1][i]);
put(ans);
return (0^_^0);
}
//以吾之血,祭吾最后的亡魂

 

树形DP 枚举祖宗的例题的更多相关文章

  1. 【动态规划】树形DP完全详解!

    蒟蒻大佬时隔三个月更新了!!拍手拍手 而且是更新了几篇关于DP的文章(RioTian狂喜) 现在赶紧学习和复习一下树形DP.... 树形DP基础:Here,CF上部分树形DP练习题:Here \[QA ...

  2. POJ 1463 Strategic game(树形DP入门)

    题意: 给定一棵树, 问最少要占据多少个点才能守护所有边 分析: 树形DP枚举每个点放与不放 树形DP: #include<cstdio> #include<iostream> ...

  3. P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】

    前言 话说在\(Loj\)下了个数据发现这题的名字叫\(fgo\) 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 \(n\)张卡的权值为\(1 ...

  4. [提升性选讲] 树形DP进阶:一类非线性的树形DP问题(例题 BZOJ4403 BZOJ3167)

    转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7337179.html 树形DP是一种在树上进行的DP相对比较难的DP题型.由于状态的定义多种多样,因此解法也五 ...

  5. poj 3140 Contestants Division(树形dp? dfs计数+枚举)

    本文出自   http://blog.csdn.net/shuangde800 ------------------------------------------------------------ ...

  6. 树形dp 入门

    今天学了树形dp,发现树形dp就是入门难一些,于是好心的我便立志要发一篇树形dp入门的博客了. 树形dp的概念什么的,相信大家都已经明白,这里就不再多说.直接上例题. 一.常规树形DP P1352 没 ...

  7. 树形dp|无根树转有根树|2015年蓝桥杯生命之树

    2015年蓝桥杯第十题--生命之树(无根树dfs) ①暴力解法:枚举子集(选点) + dfs判断连通性(题目要求连通)满足上面两个条件下找出最大值权值和 ②dfs无根树转有根树,递归找最优 先学习无根 ...

  8. 算法复习——树形dp

    树形dp的状态转移分为两种,一种为从子节点到父节点,一种为父节点到子节点,下面主要讨论子节点到父亲节点的情况: 例题1(战略游戏): 这是一道典型的由子节点状态转移到父节点的问题,而且兄弟节点之间没有 ...

  9. 树形DP(超详细!!!)

    一.概念 1.什么是树型动态规划 树型动态规划就是在“树”的数据结构上的动态规划,平时作的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有二种方法既顺 ...

随机推荐

  1. Android仿QQ空间发表动态

    效果展示图: 功能描述:用户点击+会进入发表动态的界面,发表成功后跳转到个人首页. 后续完善:增加个人头像的上传,对界面进行优化,增加点赞和评论的功能. 主要采用listview对内容进行展示,对sq ...

  2. 10.6Java学习

    1.类,对象,方法的定义.2.标识符分为两类:关键字/常见的基本类型:boolean(布尔型),byte(字节型),char(字符型),double(双精度),float(浮点),int(整型),lo ...

  3. 解决idea debugger Frames are not available

    现象:idea2017.3.7 sofaboot项目debugger报错 Frames are not available. 之前好用,不知道为啥突然不能debugger,run能正常运行代码.如下图 ...

  4. Nginx系列(7)- Nginx安装 | Linux

    step-1 安装gcc 安装 nginx 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,则需要安装: [root@localhost ~]# yum install ...

  5. Shell系列(16)- 环境变量配置文件简介及source命令

    变量类型 用户自定义变量(本地变量) 环境变量 预定义变量 位置参数变量 source命令 [root@localhost ~]# source 配置文件 或 [root@localhost ~]# ...

  6. Shell系列(38)- 数组操作→取值、遍历、替换、删除

    引言 在Linux平台上工作,我们经常需要使用shell来编写一些有用.有意义的脚本程序.有时,会经常使用shell数组.那么,shell中的数组是怎么表现的呢,又是怎么定义的呢?接下来逐一的进行讲解 ...

  7. LR集合点策略

    给大家分享一个LR集合点策略,跑并发脚本时,一定要设置策略,要不然得出的响应时间无意义.默认选择第一个(当所有虚拟用户中的x % 到达集合点进释放,即仅当指定百分比的虚拟用户到达集合点时,才释放虚拟用 ...

  8. k8s-PodApi对象

    init容器 pod的生命周期钩子 资源限制 podApi对象概览 apiVersion + kind  一个是版本 一个是资源组  共同确定当前yaml由谁来管理 metadata元数据 用来唯一标 ...

  9. turtle color设置的几种方式

    t.colormode() 查看色彩模式,缺省1.0,即RGB范围在0-1 模式切换:参数填1.0或255 t.colormode(1.0) t.colormode(255) 设置颜色,以设置penc ...

  10. P5644-[PKUWC2018]猎人杀【NTT,分治】

    正题 题目链接:https://www.luogu.com.cn/problem/P5644 题目大意 \(n\)个人,每个人被选中的权重是\(a_i\).每次按照权重选择一个没有死掉的人杀死,求第\ ...