Codeforce Problem C. Mixing Water
数学、细心
这题也是个教训!! 唉,我真是一直都被狠狠地教训着!!!
题意:
你有一个无限大的水桶,有无限杯热水温度为h,有无限杯凉水温度为c,给你一个温度t
你先倒热水一杯,再倒凉水一杯,求你最少到多少杯后能最大的接近温度t?即|t - m|最小
其中m为混合出的温度.m为凉水热水的混合平均值
数据范围:1<=c<h<=1e6, c<=t<=h
这题不难,确实不难。
我们将杯数n分为奇数偶数讨论,偶数的话温度恒为(h+c)/2
这样我们不妨令杯数为最小的2。
那么关键是杯数为奇数时的情况了。
杯数为奇数时温度为((k+1)h+kc)/(2k+1) n = 2k+1 ,k大于等于0,记为C(k)
对这个式子化简可以看到为 (h+c)/2 + (h-c)/(4k+2) > (h+c)/2
那么当t<=(h+c)/2时,cout<<2<<endl;
当t>(h+c)/2时,我们计算C(k) = t,取k的整数。
然后比较|C(K)-t| 与 |C(k+1)-t| 与 |(h+c)/2-t|
就可以了。谁小答案是谁.若相等则看谁的杯数小是谁
其实可以不比较(h+C)/2的,当然比了 答案也不会有变化。
我们,可以用排序比较的。
但这一题中我被坑的地方是在计算|C(k) - t|时的情况。
我在一开始时是这样做的:
fabs(((k+1)*h+k*c)/(2*k+1)-t)
但是我看了一下数据范围,1<=c<h<=1e6, c<=t<=h
很快我发现了不应该这样写,这可能会导致k*h过大,溢出,
因此,我将其转为:
fabs((h+c)/2.0 + (h - c) / (4 * k + 2) - t)
自信满满的我将其提交上去了,WA,哈哈哈哈哈哈。。。。。
而且一直都是在test4时错了,怎么都找不到哪里错的。。。。。。。。烦烦烦!!
后来,测试用例开放,我经过调试,问人。。。才终于知道自己错哪了。。
看到上面的式子吗?将其改一下:
fabs((h+c)/2.0 - t + (h - c) / (4 * k + 2))
没错,者的就就是这样改一下,答案就正确了。
原因是,double 的精度问题,当k达到一定程度时,小数点后位数太多,double不够用,
因此要把和(h+c)/2,0相近的t剪掉,他两人先运算,避免运算误
差太大。。。。
真的是学到了!!!!!
代码如下,注意细节:
#include<algorithm>; #include<iostream>; using namespace std; #define foru(i, a, b) for(auto i=(a);i<(b);++i) #define ford(i, a, b) for(auto i=(a);i>(b);--i) #define maxn 10005 typedef long long ll; inline int read() { char ch = getchar(); int f = 1, x = 0; while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return f * x; } int main() { int T = read(), h, c, t, ans; double mid, temp; while (T--) { h = read(), c = read(), t = read(); mid = (h + c) / 2.0; if (h <= t) cout << 1 << endl; else if (mid >= t) cout << 2 << endl; else { ans = ((h - mid) * 1.0 / (t - mid) - 1) / 2; if (fabs(mid - t + (h - mid) * 1.0 / (2.0 * ans + 1)) <= fabs(mid - t + (h - mid) * 1.0 / (2.0 * ans + 3))) cout << 2 * ans + 1 << endl; else cout << 2 * ans + 3 << endl; } } return 0; }
亏我死磕了一晚上。。。。。。。。