BZOJ 4753 二分+树形DP

思路:

先二分答案

f[x][j]表示在x的子树里选j个点

f[x][j+k]=max(f[x][j+k],f[x][j]+f[v[i]][k]);

初始化

x!=0 -> f[x][1]=p[x]-s[x]*mid

x=0 -> f[x][0]=0

类似4033的那样转移 看似O(n^3)实际O(n^2)

加一个二分 复杂度O(能过)

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2505;
int n,K,s[N],p[N],r[N],first[N],next[N],v[N],tot,size[N];
double f[N][N],mid;
void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
void dfs(int x){
    if(x){size[x]=1;f[x][1]=p[x]-s[x]*mid;}
    else size[0]=0,f[0][0]=0;
    for(int i=first[x];~i;i=next[i]){
        dfs(v[i]);
        for(int j=size[x];j>=0;j--){
            for(int k=size[v[i]];k>=0;k--){
                f[x][j+k]=max(f[x][j+k],f[x][j]+f[v[i]][k]);
            }
        }
        size[x]+=size[v[i]];
    }
}
int main(){
    memset(first,-1,sizeof(first));
    scanf("%d%d",&K,&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&s[i],&p[i],&r[i]);
        add(r[i],i);
    }
    double l=0,r=0x3f3f3f;
    while(r-l>1e-5){
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                f[i][j]=-0x3f3f3f;
        mid=(l+r)/2;
        dfs(0);
        if(f[0][K]>0)l=mid;
        else r=mid;
    }
    printf("%.3lf\n",l);
}
时间: 2024-10-13 00:25:38

BZOJ 4753 二分+树形DP的相关文章

Codeforces 627D Preorder Test(二分+树形DP)

题意:给出一棵无根树,每个节点有一个权值,现在要让dfs序的前k个结点的最小值最大,求出这个值. 考虑二分答案,把>=答案的点标记为1,<答案的点标记为0,现在的任务时使得dfs序的前k个节点都为1. 考虑树形DP. 用dp[u]表示从节点u开始在子树中进行dfs最多可以经过多少个为1的结点,显然,若某一个子树中节点全为1,那么这个可以加到dp[u]中,此外还可以在不全为1的子树中挑选一个加到dp[u]上. 那么答案就是从标记为1的节点当做根,选两颗不完全子树和所有的完全子树(包括从父亲向上的

HDU 3586 Information Disturbing(二分+树形dp)

http://acm.split.hdu.edu.cn/showproblem.php?pid=3586 题意: 给定一个带权无向树,要切断所有叶子节点和1号节点(总根)的联系,每次切断边的费用不能超过上限limit,问在保证总费用<=m下的最小的limit. 思路: 对于上限limit我们可以二分查找.然后就是树形dp,看代码就可以理解的. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring>

bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操【二分+树形dp】

二分答案,然后dp判断是否合法 具体方法是设f[u]为u点到其子树中的最长链,每次把所有儿子的f值取出来排序,如果某两条能组合出大于mid的链就断掉f较大的一条 a是全局数组!!所以要先dfs完子树才能填a!! #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1000005; int n,m,h

HDU 3586 Information Disturbing (二分+树形dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3586 给定n个敌方据点,1为司令部,其他点各有一条边相连构成一棵树,每条边都有一个权值cost表示破坏这条边的费用,叶子节点为前线.现要切断前线和司令部的联系,每次切断边的费用不能超过上限limit,问切断所有前线与司令部联系所花费的总费用少于m时的最小limit.1<=n<=1000,1<=m<=10^6 dp[i]表示i节点为root的这个子树所破坏的最少费用,if(cost[i]

【BZOJ2525】[Poi2011]Dynamite 二分+树形DP

[BZOJ2525][Poi2011]Dynamite Description Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸.药,现在需要点燃M个点上的引线引爆所有的炸.药. 某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃.如果一个有炸.药的点的引信被点燃,那么这个点上的炸.药会爆炸. 求引爆所有炸.药的最短时间. 输入: 第一行是两个整数N,M.(1<=m<=n<=300000) 接下来一行有N个整数Di,第I个数为1表示该点

bzoj 1131 简单树形dp

思路:随便想想就能想出来啦把...  卡了我一个vector... #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define pii pair<int,int> #define piii pair<int, pair<int,int> > using namespace std; const int

BZOJ 3004 吊灯 树形DP

题目大意:给定一棵树,要求将这棵树分成nk个连通块,每块大小为k,求所有可行的k 首先k一定是n的约数.(废话 然后我们有一个结论:某个k满足条件当且仅当存在nk个节点满足以每个节点为根的子树大小都是k的倍数 证明: 首先不可能存在超过nk个节点满足以每个节点为根的子树大小都是k的倍数,这是废话 首先证明必要性: 假设我们已经有了一组合法的方案,那么对于每一个连通块,我们找到这个连通块中深度最小的节点,以这个节点为根的子树大小一定是k的倍数 由于这样的节点有nk个,因此必要性得证 下面来证明充分

hdu3586 树形dp+二分求解

http://acm.hdu.edu.cn/showproblem.php?pid=3586 Problem Description In the battlefield , an effective way to defeat enemies is to break their communication system. The information department told you that there are n enemy soldiers and their network w

BZOJ 1093 最大半连通子图(强连通分量+树形DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1093 题意: 思路:(1)首先,强连通分量中的一个点若在最大半连通子图中,则必定整个连通分量中的点都在,因为都在还是满足半连通的性质而且使得节点数更多. (2)因此,求出强连通分量缩点,形成一个有向无环图,其实与树是差不多的.在这个图上DP一次即可,也就是找出最长链以及最长链的个数. vector<int> g[N],g1[N]; int n,m,mod; int dfn[N],lo