题解 AT1807 【食塩水】

encore

2019-02-15 17:06:10

Solution

先说吧,这题是二分答案。~~你不知道我DP做了多久QAQ。~~ 一道很有意思的二分题。我们假设最终答案为$x$。显然有 $ 0 \leq x \leq 100 $。当然你可以说$x$一定大于最小的那个浓度之类,不过无所谓,反正不差那么点时限。 然而只知道二分并没有什么卵用,解决这题还需要一个贪心策略。如果你稍微做过一会儿你就知道,并不是浓度越大越好的。 设所有盐水的集合为$S$。我们假设选取了$S_{a_1}$、$S_{a_2}$、$S_{a_3}$、……$S_{a_k}$这$k$瓶。现在我们来判断这$k$瓶盐水能不能混合出浓度大于$x\%$的盐水。很显然,新的盐水的浓度为: $\frac{w_{a_1} p_{a_1} +w_{a_2} p_{a_2} +w_{a_3} p_{a_3} +...+w_{a_k} p_{a_k}}{w_{a_1}+w_{a_2}+w_{a_3}+...+w_{a_k}}$ 。 那么只要 $\frac{w_{a_1} p_{a_1} +w_{a_2} p_{a_2} +w_{a_3} p_{a_3} +...+w_{a_k} p_{a_k}}{w_{a_1}+w_{a_2}+w_{a_3}+...+w_{a_k}} \geq x$就说明当前选取的$x$可行。 然后我们将上面的式子变形: $w_{a_1} p_{a_1} +w_{a_2} p_{a_2} +w_{a_3} p_{a_3} +...+w_{a_k} p_{a_k} - x\times (w_{a_1} +w_{a_2}+w_{a_3}+...+w_{a_k}) \geq 0$ 然后…… $w_{a_1} (p_{a_1}-x) +w_{a_2} (p_{a_2}-x) +w_{a_3} (p_{a_3}-x) +...+w_{a_k} (p_{a_k}-x) \geq 0$ 好像没什么啊?但是我们可以发现,当$x$确定的时候,对于所有的$S_i$,它的$w_i (p_i - x)$ 都是确定的。选取$S_i$对应的$w_i (p_i - x)$一定是越大越好啦。所以在我们二分答案$x$的时候,只要处理出所有的$w_i (p_i - x)$,再按照$w_i (p_i - x)$的值从大到小选取盐水,就可以得到对于当前的$x$最优解。如果这个解符合,说明我们的$x$小于等于答案,如果不符合则相反。 基本差不多了,不过要注意精度之类的细节啊。下面贴AC代码: ````cpp #include <cmath> #include <iomanip> #include <iostream> #include <queue> using namespace std; typedef long double ld; const int maxn = 1001, maxk = 1001; int n, k; ld p[maxn], w[maxn]; inline ld check(ld val) { priority_queue<ld> v;//用来排序,vector加sort也一样的 for (register int i = 1; i <= n; ++ i) { v.push(w[i] * (p[i] - val)); } ld sum = 0; for (register int i = 1; i <= k; ++ i) { sum += v.top(); v.pop(); } return sum; } int main(void) { cin >> n >> k; for (register int i = 1; i <= n; ++ i) cin >> w[i] >> p[i]; ld l = 0, r = 100, mid = 1, mid_old = 0; while (abs(mid - mid_old) >= 1e-10) { //自创沙雕二分 mid_old = mid; mid = 0.5 * (l + r); ld tmp = check(mid); if (tmp > 0) l = mid; else r = mid; } cout.setf(ios::fixed); cout << setprecision(9) << mid << endl; //保留九位小数, cout.unsetf(ios::fixed); //头文件<iomanip> return 0; } ```` 最后给你们看看我的WA提交记录。。。 [https://www.luogu.org/recordnew/show/16347998](https://www.luogu.org/recordnew/show/16347998) [https://www.luogu.org/recordnew/show/16348654](https://www.luogu.org/recordnew/show/16348654)