题目

睿智题,二分一下点权变成了\(P_i-S_i\times mid\),树上背包一下求一个大小为\(m+1\)的点权大于\(0\)的联通块即可

所以我为啥写这题来着

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define eps 1e-7
#define inf 1e15
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=2503;
struct E{int v,nxt;}e[maxn];
int head[maxn],n,num,m,sum[maxn],p[maxn],s[maxn];
inline void add(int x,int y) {
    e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
double dp[maxn][maxn],w[maxn];
void dfs(int x) {
    sum[x]=1;dp[x][1]=w[x];
    for(re int i=head[x];i;i=e[i].nxt) {
        dfs(e[i].v);sum[x]+=sum[e[i].v];
        for(re int j=min(sum[x],m);j;--j)
            for(re int k=0;k<=min(sum[e[i].v],m)&&j-k>=0;++k)
                dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[e[i].v][k]);
    }
    dp[x][0]=0;
}
inline void Solve(double mid) {
    for(re int i=0;i<=n;i++) w[i]=p[i]-s[i]*mid;
    for(re int i=0;i<=n;i++)
        for(re int j=0;j<=m;j++) dp[i][j]=-inf;
    dfs(0);
}
int main() {
    m=read()+1,n=read();
    for(re int x,i=1;i<=n;i++)
        s[i]=read(),p[i]=read(),x=read(),add(x,i);
    double l=0,r=4e7;
    while(r-l>eps) {
        double mid=(l+r)/2.0;
        Solve(mid);
        if(dp[0][m]>0) l=mid;else r=mid;
    }
    printf("%.3lf\n",l);
    return 0;
}
01-22 01:30
查看更多