首页 > 代码库 > BZOJ 4753 二分+树形DP

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);}

 

BZOJ 4753 二分+树形DP