题目大意:
热水温度为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
这样,我们总能找到最优的次数。