這種最大化形如∑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個人,...