BZOJ4753 [Jsoi2016] best group [tree backpack] [dichotomy]

Keywords: PHP

Title Link: https://www.lydsy.com/JudgeOnline/problem.php?id=4753

Explanation:
For the final answer, the floating-point dichotomy is performed, and for each midmid ID, dpdp is performed.
Let dp[i][j]dp[i][j] indicate that the maximum weight of jj nodes (∑ ni=1(p[i] − cur * s[i]) ∑ i=1n(p[i] − cur * s[i])) has been selected considering the second node and its subtree of dfs order. The latter formula can be preprocessed for each bisection.
Note that we need to do dpdp in the dictionary order, so we can do dfsdfs before dichotomy.
Next, the problem becomes: to select several numbers, if you want to select node ii, you must select the left and right ancestors of ii, which is a dependent knapsack. There are two situations in each dpdp:
(1) (1) point ii:
dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]+d[i]);dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]+d[i]);
(2) (2) the second point is not selected:
dp[to[i]][j]=max(dp[to[i]][j],dp[i][j]);dp[to[i]][j]=max(dp[to[i]][j],dp[i][j]);
Where to[i]to[i] represents the last node of the dfsdfs order of the subtree where the second point of the dfsdfs order is located. This can be pre processed at the beginning of the dfsdfs.
Then the answer is whether dp[i][k+1]dp[i][k+1] has an ii that makes DP [i] [K + 1] > = epsdp [i] [K + 1] > = EPS. Notice that because I write dpdp in the push method, the answer is k+1k+1 instead of kk.
Pay attention to the precision of floating-point numbers. I use epseps to take 1E − 71e − 7

Code:

// by Balloons
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;

typedef long long LL;

const int inf = 1 << 30;
const double eps=1e-7;

const int maxn=2505;
int k,n;
int s[maxn],p[maxn],r[maxn]; 
vector<int>tree[maxn];
int dfn[maxn],dfs_clock=0,to[maxn];
// dp[i][j] means that considering the i-th node and its subtree, the maximum weight of j-th node has been selected (sigma (p[i]-cur*s[i]) 
double dp[maxn][maxn],d[maxn];

// The order of dfs, i and the most reachable order of the subtree can be obtained by dfs preprocessing 
void dfs(int now){
    dfn[now]=dfs_clock++;
    for(int i=0;i<tree[now].size();i++){
        int u=tree[now][i];
        dfs(u);
    }
    to[dfn[now]]=dfs_clock;
}

int check(double cur){
    // The weight of the person whose order of dfs is i 
    for(int i=1;i<=n;i++)d[dfn[i]]=1.0*p[i]-cur*s[i];
    // Node 0 must be selected 
    for(int i=1;i<=n+1;i++)
        for(int j=0;j<=k+1;j++)dp[i][j]=-1e9;
    for(int i=0;i<=n;i++){
        for(int j=0;j<=min(i,k);j++){ 
            // If the current node is selected, if it is not the last node in the dfs order of its subtree, and the parent node is selected, it will be updated (plus the weight) 
            if(to[i]!=i&&dp[i][j]!=-1e9)dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]+d[i]);
            // If the current node is not selected, it is directly updated to the next node of the non-i subtree 
            if(dp[i][j]!=-1e9)dp[to[i]][j]=max(dp[to[i]][j],dp[i][j]); 
        }
    } 
    // Judge, if there is a selection method that can meet the conditions, ok 
    for(int i=0;i<=n+1;i++)
        if(dp[i][k+1]>=eps)return 1;
    return 0;
}

int main(){
    scanf("%d%d",&k,&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&s[i],&p[i],&r[i]);
        tree[r[i]].push_back(i);
    }
    dfs(0);
    double l=0.0,r=10000.0,ans;
    while(l+eps<=r){
        double mid=(l+r)/2.0;
        if(check(mid)){
            ans=mid;
            l=mid;
        }else r=mid;
    }
    printf("%.3f\n",ans);

    return 0;
}

Posted by zypher11 on Wed, 01 Jan 2020 04:52:11 -0800