【題目翻譯】
有一個無限大的容器。你輪流進行如下操作:倒一杯熱水進去、倒一杯冷水進去。以此類推。
(熱水溫度是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;
}