@Junlier
2018-10-18T15:06:05.000000Z
字数 1641
阅读 2055
看到分数和最值,考虑分数规划
我们要求的是一个最大对吧,考虑二分一个答案
那么就会有合法条件,化简一下:
所以每次二分一个之后得到一个新数组v[i]=P[i]-S[i]×mid,我们跑背包它最后是否大于等于就可以了,因为有约束条件,所以把树建出来跑树上背包
dp[i][j]表示节点选了个凑出的的最大值,我们最后就只要判断dp[0][K+1]>=0就可以啦
等一下!
这个的转移看上去向的啊,再乘上的的复杂度不就复杂度假了吗
其实不然,总体来看,每一对节点的状态只会在他们的处被转移一次,想一想为什么(我想了挺久),所以复杂度就是的啦
然而它还是卡常啊,最后就卡了很久,终于卡过去了。。。
#include<bits/stdc++.h>#define il inline#define rg register#define ldb double#define lst long long#define rgt register int#define N 2550#define pb push_back#define qw G[now][i]using namespace std;const lst Inf=1e18;const ldb eps=1e-4;il int read(){int s=0,m=0;char ch=getchar();while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();return m?-s:s;}int K,n,Dex;int siz[N];struct LJL{int S,P,fa;}ljl[N];ldb v[N],tmp[N],dp[N][N],Ans;vector<int> G[N];il void Merge(rgt x,rgt y){for(rgt i=0;i<=K+1;++i)tmp[i]=-Inf;for(rgt i=1,up;i<=siz[x];++i){up=min(K+1-i,siz[y]);for(rgt j=1;j<=up;++j)tmp[i+j]=max(tmp[i+j],dp[y][j]+dp[x][i]);}for(rgt i=0;i<=K+1;++i)dp[x][i]=max(dp[x][i],tmp[i]);}void Dfs(rgt now){for(rgt j=0;j<=K+1;++j)dp[now][j]=-Inf;dp[now][1]=v[now],siz[now]=1;for(rgt i=0;i<G[now].size();++i)Dfs(qw),Merge(now,qw),siz[now]+=siz[qw];}il bool check(ldb lim){for(rgt i=1;i<=n;++i)v[i]=ljl[i].P-ljl[i].S*lim;Dfs(0);return dp[0][K+1]>=0;}int main(){K=read(),n=read();for(rgt i=1;i<=n;++i){ljl[i]=(LJL){read(),read(),read()};G[ljl[i].fa].pb(i);}ldb le=eps,ri=1e5,mid;while(ri-le>eps){mid=(le+ri)/2;if(check(mid))Ans=mid,le=mid+eps;else ri=mid-eps;}return printf("%.3lf\n",Ans),0;}
