JSOI2016 最佳團隊

2021-07-12 07:20:26 字數 1540 閱讀 5762

這種最大化形如∑x

/∑y 的式子的題,很容易想到分數規劃。

二分答案,對於當前的mid,設d[i]=p[i]-mid*s[i]

考慮到當乙個節點i被選,那麼fa[i]也要被選,那麼乙個想法是選取當前最大的d,然後把它的兒子的d放入堆裡。

但是這個方法是錯誤的(然而我一開始就這麼打了,只有10分)

題目給出的是一棵樹,那麼可以先dfs一遍,存下每個點的dfs序,然後設f[i][j]表示當前做到dfn為i的節點,選取了j個的最大和。設r[i]為節點i的子樹中最大的dfn+1

轉移有兩種情況:

1. 選取i,設它原來的編號為x,那麼f[i][j]+a[x]——>f[i+1][j+1]

2. 不選取i,那麼f[i][j]——>f[r[i]][j] (這樣就跳過了它的子樹)

加上二分,時間複雜度為o(

n2lo

gans

)

#include 

#include

#include

using

namespace

std;

typedef

double db;

const

int maxn=2505;

const db z=1e-5,inf=-1e20;

int m,n,tot,fa[maxn],h[maxn],e[maxn],next[maxn],dfn[maxn],r[maxn];

db d[maxn],s[maxn],p[maxn],f[maxn][maxn],l,r,mid,ans;

void add(int x,int y)

void init(int x)

int main()

tot=0;

init(0);

for (l=0,r=1e4,mid=r/2;r-l>=z;mid=(l+r)/2)

for (int j=0;j<=m+1;j++) f[n+1][j]=inf;

for (int i=0;i<=n;i++)

for (int j=0;j<=min(i,m+1);j++)

if (f[n+1][m+1]>=0) l=mid;else r=mid;

}printf("%.3lf\n",mid);

return

0;}

JSOI2016 最佳團隊

看到這個什麼比值最大,立馬想到了二分答案。然後就變成了乙個樹上揹包問題,直接暴力合併揹包即可。暴力合併不是o n3 的嗎?記錄一下子樹的大小,揹包時的上界設為這個,就降成o n2 感性證明 你可以想象兩個點只會在它們的lca處合併。code include include define fd i,x...

JSOI2016 最佳團隊

這題,二分 樹上揹包即可。由於答案要最大 最值 所以我們可以二分。然後我們可以簡化一下答案。那麼每個點的貢獻即為 p i mid s i 做樹上揹包,看一下f 0 k 是否大於0即可。上標 include include include define db double using namespac...

JSOI 2016 最佳團體

有 n n 名候選人,從 1 role presentation 11到 n n 編號,有乙個隊長的編號為 0 role presentation 0 0,每個候選人都由一位編號比他小的候選人推薦 如果為 0 0 則表示是隊長推薦的 隊長希望招募 k role presentation k k個人,...