Description

JSOI 信息学代表队一共有 \(n\) 名候选人, 这些候选人从 \(1\)\(n\) 编号. 方便起见, JYY 的编号是 \(0\) 号. 每个候选人都由一位编号比他小的候选人 \(R_i\) 推荐. 如果 \(R_i=0\) 则说明这个候选人是 JYY 自己看上的.

为了保证团队的和谐, JYY 需要保证, 如果招募了候选人 \(i\), 那么候选人 \(R_i\) 也一定需要在团队中. 当然了, JYY 自己总是在团队里的. 每一个候选人都有一个战斗值 \(P_i\), 也有一个招募费用 \(S_i\). JYY 希望招募 \(K\) 个候选人 (JYY 自己不算), 组成一个性价比最高的团队.

也就是, 这 \(K\) 个被 JYY 选择的候选人的总战斗值与总招募总费用的比值最大.

Input

输入一行包含两个正整数 \(K\)\(n\).

接下来 \(n\) 行, 其中第 \(i\) 行包含 \(3\) 个整数 \(S_i, P_i, R_i\) 表示候选人 \(i\) 的招募费用, 战斗值和推荐人编号.

Output

输出一行一个实数, 表示最佳比值. 答案保留三位小数.

Sample Input

1 2
1000 1 0
1 1000 1

Sample Output

0.001

Data Range

对于 100% 的数据, 满足:\(1 \leq K \leq n \leq 2500, 0 \leq S_i, P_i \leq 10^4, 0 \leq R_i \lt i\).

Explanation

属于 \(0-1\) 分数规划问题, 题目要求的是最大化:\[ \begin{aligned} & ans = \frac{\sum_{i=1}^{n} P_i}{\sum_{i=1}^{n} S_i}\\ & \forall i \in ans, R_i \in ans \end{aligned} \] 需要二分 \(ans\) 的值, 使得这个玩意儿可以用 \(0-1\) 背包来解决.

我们成功把一个奇怪的问题转化成了树上背包......

另外注意精度问题.

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>

using namespace std;
typedef long long lli;
typedef double llf;
const int maxn = 2510, maxm = 5010;
const llf epsilon = 1e-8;
const llf infinit = 1e9;

struct edge
{
    int u, v;
    edge *next;
};

int root, ecnt;
edge *edges[maxn], epool[maxm];
int par[maxn];
void set_child(int u, int v)
{
    edge *p = &epool[++ecnt];
    p->u = u; p->v = v;
    p->next = edges[u]; edges[u] = p;
    par[v] = u;
    return ;
}

int m, n;
int a[maxn], b[maxn]; // Required calculation of b/a
int siz[maxn];
llf v[maxn], f[maxn][maxn], g[maxn];

void build(llf x)
{
    for (int i = 0; i <= n; i++) {
        v[i] = a[i] - x * b[i];
        for (int j = 0; j <= n; j++)
            f[i][j] = -infinit;
    }
    return ;
}
void update(int x, int y)
{
    // Tempoorary array: g[]
    for (int i = 0; i <= siz[x] + siz[y]; i++)
        g[i] = -infinit;
    for (int i = 0; i <= siz[x]; i++)
        for (int j = 0; j <= siz[y]; j++)
            g[i+j] = max(g[i+j], f[x][i] + f[y][j]);
    siz[x] += siz[y];
    for (int i = 0; i <= siz[x]; i++)
        f[x][i] = max(f[x][i], g[i]);
    return ;
}
void dfs(int x)
{
    siz[x] = 0;
    f[x][0] = 0;
    for (edge *ep = edges[x]; ep; ep = ep->next) {
        dfs(ep->v);
        update(x, ep->v);
    }
    for (int i = siz[x]; i >= 0; i--)
        f[x][i+1] = f[x][i] + v[x];
    siz[x] += 1;
    f[x][0] = 0;
    return ;
}

int main(int argc, char** argv)
{
    scanf("%d%d", &m, &n);
    m += 1; // Himself
    for (int i = 1, x; i <= n; i++) {
        scanf("%d%d%d", &b[i], &a[i], &x);
        set_child(x, i);
    }
    // Binary search for results?
    llf res = 0.0, l = 0.0, r = 10000.0;
    while (fabs(r - l) > epsilon) {
        llf mid = (l + r) / 2;
        build(mid);
        dfs(0);
        if (f[0][m] > 0) {
            res = mid;
            l = mid;
        } else {
            r = mid;
        }
    }
    // Result
    printf("%.3lf\n", res);
    return 0;
}