CodeForces

CF1359C Mixing Water

题目大意:

热水温度为h,冷水温度为c,不断以热水、冷水、热水、冷水……的顺序加入桶中,桶中的温度为加入过的水的平均值,问多少次操作后使桶中的温度最接近给定的温度t。

思路:

注意题目条件$ c leq h leq 10^6$,可以分成三种情况进行讨论。

如果 (h == t),一次就好。

如果 $ t leq frac{h + c}{2}$,因为最低温度不会低于第二次(即平均值)的温度,两次就好。

else,我们稍微推一下数据就可以发现,如果忽视掉(frac{h+c}{2})温度对应的次数,那么操作后的温度满足单调递减,于是我们想到可以二分查找加水的次数。

Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PI;
const double eps = 1e-6;
const int N = 200010;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007; //998244353
LL powmod(LL a, LL b) { LL res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1)res = res * a % mod; a = a * a % mod; }return res; }

LL h, c, t; 

double f(double x) {
    return (x * (h + c) + h) / (2 * x + 1);
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T--) {
        cin >> h >> c >> t;
        if (h == t) { cout << 1 << endl; continue; }
        if (h + c >= 2 * t) { cout << 2 << endl; continue; }
        LL lb = 0, rb = INF;
        while (lb < rb) {
			LL mid = (lb + rb + 1) / 2; //向上取整保证可行域的完整性
			if (f(1.0 * mid) >= 1.0 * t) {
				lb = mid;
			} else {
				rb = mid - 1;
			}
			// cout << "lb = " << lb << " rb = " << rb << endl;
		}
		rb = lb + 1;
		if (f(lb) - 1.0 * t > 1.0 * t - f(rb)) {
            cout << 2 * rb + 1 << endl;
        } else cout << 2 * lb + 1 << endl;
    }
    return 0;
}

在查找出加水的次数之后我们使(rb=lb+1),原因是:

case 1:
        * t
*----------*----------*
lb         rb

case 2:
              * t
*----------*----------*
           lb         rb

case 3:
        * t
*----------*----------*
           lb         rb

case 4:
              * t
*----------*----------*
lb         rb

这样,我们总能找到最优的次数。

原文地址:https://www.cnblogs.com/Nepenthe8/p/14310889.html