P1984 [SDOI2008]烧水问题(具体证明)
我见过的第二恶心的题,第一是糖果传递...
以下是一堆具体的证明,自己想的,可能考虑不周,不想看也可以直接看结论
首先有一个很显然的贪心,烧开的水要尽量把热量传递出去
所以有一个比较显然的方法:每杯水烧开后都与下一杯水热传递,平衡后再把剩下的温度与更后面一杯水热传递,这样一直下去...
十分显然把热量传递出去比不传递出去要更优
具体证明:设下一杯水温度为 $t_1$,此时上一杯水已经烧开,为$t_{max}$
如果它们之间进行热传递,那么下一杯水的热量就变成 $\frac{t_1+t_{max}}{2}$
显然温度会更高,所以烧开所需热量更少,答案会更优,并且可以容易推广到多杯水的情况
然后热量传出去了,按什么顺序烧开他们也是关键
方法:把温度从大到小排序,优先烧温度大的水再把热量传下去会更优
证明:设第一杯水温度为 $t_1$ ,第二杯水温度为 $t_2$,且 $t_1>t_2$
如果我们先烧第一杯水,那么需要升高的温度为 $t_{max} - t_1$
然后第一杯水烧开后再把热量传给第二杯水,第二杯水温度变成 $\frac{t_2+t_{max}}{2}$
把第二杯水烧开需要升高的温度为 $t_{max} - \frac{t_2+t_{max}}{2}$
因为水质量一样,所以升高的温度可以直接相加,化简得$\frac{3}{2}t_{max} - t_1 -\frac{t_2}{2}$
因为水的质量一样,所以温度的升高多少就相当于热量的消耗多少
如果我们先烧第二杯水再传温度给第一杯水再烧第一杯水
经过同样的方法可以算出总共升高的温度为$\frac{3}{2}t_{max} - t_2 -\frac{t_1}{2}$
因为 $t_1>t_2$ ,所以第一种方案更优,此结论用同样的方法也能推广到多杯水的情况
所以总结一下,就是优先烧温度大的水,然后把热量尽量传出去
知道了方案,每杯水消耗的热量自己找找规律就出来了
设 $f_n$ 表示第 n 杯水烧开消耗的热量
那么 $f_n=f_{n-1}*[1-\frac{1}{2}(n-1)]$
代码不解释
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<cstring> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int n; double ans,now=420000.0; int main() { n=read(); now/=n; for(int i=1;i<=n;i++) ans+=now,now*=(1-0.5/i); printf("%.2lf",ans); return 0; }