【Educational Codeforces Round 88 (Rated for Div. 2) C】 Mixing Water
【题目翻译】
有一个无限大的容器。你轮流进行如下操作:倒一杯热水进去、倒一杯冷水进去。以此类推。
(热水温度是h,冷水温度是c)
容器中的水的温度等于倒进去的水的温度总和/倒水的次数。
问你需要进行多少次操作,水的温度才能最接近温度t。
【题解】
会发现,进行2,4,6,8,10...次操作,水的温度都是(h+c)/2.并且因为是先倒热水,所以在水的温度的变化过程中,水温始终是大于(h+c)/2.
因此,对于给定的温度t如果是<=(h+c)/2,那么直接输出2就行了,因为那是你能到达的最小的温度了(然后操作次数最少).
因为2,4,6,8...这些正偶数操作次数水温都是\(\frac{h+c}{2}\),所以我们不考虑他们了。
直接考虑操作次数为1,3,5,...的,然后发现这些操作对应的水温是一个单调递减的数字(试出来的,嘻嘻)(如果t给的值等于h,则直接输出1)
然后就写个二分,找到最小的小于t的温度对应的操作次数(我这里二分的是它是1,3,5,...中的第几个,第x个对应了第1+x*2次操作)就好。
然后和第i-2次操作比较一下,看哪个温度和t距离比较近(相等的话输出i-2)
二分的上限一开始是50W(这个数字是我大概根据比较大的数字的出来的迭代次数),交上去WA了,然后就加了个0,再交了一发。
当时只剩5分钟了,我提交的结果都没敢去看。。直接去检查细节去了。没检查出来什么东西,然后回过头看看提交结果,YES!!!
不过这会还没hack结束,不知道会不会挂终测:)
【代码】
#include<bits/stdc++.h>
#define ll long long
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%I64d",&x)
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
using namespace std;
const int N = 1000;
int T;
int main(){
//cout<<(1LL<<62)<<endl;
#ifdef LOCAL_DEFINE
freopen("D:\\rush.txt","r",stdin);
#endif
ios::sync_with_stdio(0),cin.tie(0);
cin >> T;
while (T--){
int h,c,t;
cin >> h >> c >> t;
if (t*2<=h+c){
cout<<2<<endl;
}else{
if (t==h){
cout<<1<<endl;
}else{
//h/2<t<h
ll tmp;
double pans = h-t;
ll l = 1,r = 5000000,temp = 0;
while (l<=r){
ll mid = (l+r)/2;
ll i = 1+mid*2;
tmp = h + (h+c)*mid;
if (tmp%i==0){
if (tmp/i==t){
temp = mid;
break;
}
}
double fenzi = tmp;
double fenmu = i;
double ans = fenzi/fenmu;
if (ans<t){
temp = mid;
r = mid - 1;
}else{
l = mid + 1;
}
}
ll i = 1+temp*2;
tmp = h + (h+c)*temp;
if (tmp%i==0 && tmp/i==t){
cout<<i<<endl;
}else{
ll pi = i-2;
ll ptmp = tmp-h-c;
double pans = (1.0*ptmp)/(1.0*pi) - t;
double ans = t-(1.0*tmp)/(1.0*i);
if (pans<=ans){
cout<<i-2<<endl;
}else{
cout<<i<<endl;
}
}
}
}
}
return 0;
}