1. 程式人生 > >BZOJ4753: [Jsoi2016]最佳團體(分數規劃+樹上揹包)

BZOJ4753: [Jsoi2016]最佳團體(分數規劃+樹上揹包)

BZOJ4753: [Jsoi2016]最佳團體(分數規劃+樹上揹包)

標籤:題解
閱讀體驗
BZOJ題目連結 洛谷題目連結

具體實現

看到分數和最值,考慮分數規劃
我們要求的是一個\(\dfrac{\sum P_i}{\sum S_i}\)最大對吧,考慮二分一個答案\(mid\)
那麼就會有合法條件\(\dfrac{\sum P_i}{\sum S_i}\ge mid\),化簡一下:\(\sum{(P_i-S_i×mid)}\ge 0\)
所以每次二分一個\(mid\)之後得到一個新陣列v[i]=P[i]-S[i]×mid,我們跑揹包\(check\)它最後是否大於等於\(0\)就可以了,因為有約束條件,所以把樹建出來跑樹上揹包

dp[i][j]表示\(i\)節點選了\(j\)個湊出的\(v\)的最大值,我們最後就只要判斷dp[0][K+1]>=0就可以啦

等一下!
這個\(dp\)的轉移看上去向\(n^2\)的啊,再乘上\(Dfs\)\(n\)的複雜度不就複雜度假了嗎
其實不然,總體來看,每一對節點的\(dp\)狀態只會在他們的\(Lca\)處被轉移一次,想一想為什麼(我想了挺久),所以複雜度就是\(n^2\)的啦
然而它還是卡常啊,最後\(Junlier\)就卡了很久,終於\(988ms\)卡過去了。。。

程式碼

#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;
}