相关链接
题目传送门:https://arena.topcoder.com/#/u/practiceCode/15657/31723/12515/1/317358
中文题面及题解:http://picks.logdown.com/posts/208980-solutions-to-topcoder-open-2013s-hard-problems
解题报告
这题从头到尾都只会 $O(n^3)$ 的 $DP$
想了四个小时啊 QwQ
考虑搞出一个二叉搜索树
显然我们可以控制一个节点的左右儿子有多少个
因为我们可以询问当前区间的端点,所以我们还可以控制有没有左右儿子
换一句话说,我们可以钦定这棵搜索树的形态
我们继续观察可以发现一下两条:
- 我们可以根据一个节点左右儿子子树的大小,求得往左、往右走的概率
- 每一个深度在$[A,B]$的节点都是一个合法的结束
于是我们就可以枚举第$A$层有多少结点,然后贪心往下放就可以啦!
Code
#include<bits/stdc++.h> #define LL long long using namespace std; class WellTimedSearch { public: double getProbability(int n, int A, int B) { int vout = 0; for (int i=1,up,down;i<=n;i++) { if (A > 1) up = Get_Top(i+1>>1, A-1); else {if (i == 1) up = 0; else up = 1e9;} if (n - up - i < 0) break; down = Get_Down(B-A, n - up - i, i<<1); vout = max(vout, i + down); } return (double)vout / n; } private: int Get_Top(int len, int t) { if (t > 1) return min((int)1e9, len + (len>1? Get_Top(len+1>>1, t-1): t-1)); if (t == 1 && len > 1) return 1e9; return 1; } int Get_Down(int t, int num_node, int cur) { if (!t) return 0; if (cur >= num_node) return num_node; return cur + Get_Down(t-1, num_node - cur, cur<<1); } };