NAIPC 2016 D 题解

19 阅读1分钟

思路

求分数最大值,显然0101分数规划。接下来就转化成求树上包含根的权值最大联通块。树形DP即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define per(i,st,ed) for(int i=st;i>=ed;--i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
const ll N=2550;
ll k,n;
ll a[N],b[N],siz[N];
db f[N][N],c[N];
vector<ll> e[N];
void dfs(ll u)
{
	db now[N],pre[N];
	now[siz[u]=1]=c[u];
	for(auto v:e[u])
	{
		dfs(v);
		rep(i,1,siz[u])
			pre[i]=now[i];
		rep(i,2,siz[u]+siz[v])
			now[i]=-INF;
		rep(i,1,siz[u])
			rep(j,0,siz[v])
				now[i+j]=max(now[i+j],pre[i]+f[v][j]);
		siz[u]+=siz[v];
	}
	rep(i,1,siz[u])
		f[u][i]=now[i];
}
ll check(db x)
{
	rep(i,1,n)
		c[i]=b[i]-a[i]*x;
	dfs(0);
	return f[0][k+1]>=0;
}
int main()
{
	read(k,n);
	ll fa;
	rep(i,1,n)
	{
		read(a[i],b[i],fa);
		e[fa].emplace_back(i);
	}
	db L=0,R=1e4;
	rep(i,1,50)
	{
		db mid=(L+R)/2;
		if(check(mid))
			L=mid;
		else
			R=mid;
	}
	printf("%.3lf",L);
}