洛谷 P1984 [SDOI2008]烧水问题
题目
把总质量为1kg的水分装在n个杯子里,每杯水的质量均为(1/n)kg,初始温度均为0℃。现需要把每一杯水都烧开。我们可以对任意一杯水进行加热。把一杯水的温度升高t℃所需的能量为(4200*t/n)J,其中,“J”是能量单位“焦耳”。如果一旦某杯水的温度达到100℃,那么这杯水的温度就不能再继续升高,此时我们认为这杯水已经被烧开。显然地,如果直接把水一杯一杯地烧开,所需的总能量为(4200*100)J。
在烧水的过程中,我们随时可以在两杯温度不同的水之间进行热传递操作。热量只能从温度较高的那杯水传递到温度较低的那杯水。由于两杯水的质量相同,所以进行热传递操作之后,原来温度较高的那杯水所降低的温度总是等于原来温度较低的那杯水所升高的温度。
一旦两杯水的温度相同,热传递立刻停止。
为了把问题简化,我们假设:
1、没有进行加热或热传递操作时,水的温度不会变化。
2、加热时所花费的能量全部被水吸收,杯子不吸收能量。
3、热传递总是隔着杯子进行,n杯水永远不会互相混合。
4、热传递符合能量守恒,而且没有任何的热量损耗。
在这个问题里,只要求把每杯水都至少烧开一遍就可以了,而不要求最终每杯水的温度都是100℃。我们可以用如下操作把两杯水烧开:先把一杯水加热到100℃,花费能量(4200*100/2)J,然后两杯水进行热传递,直到它们的温度都变成50℃为止,最后把原来没有加热到100℃的那杯水加热到100℃,花费能量(4200*50/2)J,此时两杯水都被烧开过了,当前温度一杯100℃,一杯50℃,花费的总能量为(4200*75)J,比直接烧开所需的(4200*100)J少花费了25%的能量。
你的任务是设计一个最佳的操作方案使得n杯水都至少被烧开一遍所需的总能量最少。
输入输出格式
输入格式:
输入文件只有一个数n。
输出格式:
输出n杯水都至少被烧开一遍所需的最少的总能量,单位为J,四舍五入到小数点后两位。
输入输出样例
输入样例#1:
2
输出样例#1:
315000.00
说明
1≤n≤50000
题解
规律题
由题目的解释中我们可以知道,热传递,烧水的先后可以自己定的(这不科学 QAQ!!!)
设加热第一杯水的能量为a=420000/n
先加热第一杯水至100℃,需要a的能量;
第一杯水的热量传递给第二杯,第一杯变为50℃,第二杯变为50℃;
再加热第二杯水至100℃,需要a/2的能量;
第一杯的水的热量传给第二杯,第一杯变为25℃,第三杯变为25℃;
第二杯的水的热量传给第三杯,第二杯变为62.5℃,第三杯变为62.5℃;
(由于如果先把第二杯的水的热量传给第三杯,那么第一杯就无法传给第三杯了,所以我们先把第一杯的热量传给第三杯)
再加热第三杯水至100℃,需要3*a/8的能量;
第一杯的水的热量传给第四杯,第一杯变为12.5℃,第四杯变为12.5℃;
第二杯的水的热量传给第四杯,第二杯变为37.5℃,第四杯变为37.5℃;
第三杯的水的热量传给第四杯,第三杯变为68.75℃,第四杯变为68.75℃;
(理由同上)
再加热第四杯水至100℃,需要5*a/16的能量
……
我们可以找出一个规律,即第n+1杯需要的能量为第n杯所需能量的1-0.5/n倍
代码
#include<cstdio>
using namespace std;
int n;
double ans,now;
int main()
{
scanf("%d",&n);
ans=0;now=420000.00/n;
for (int i=1;i<=n;i+=1)
{
ans+=now;
now*=(1-0.5/i);
}
printf("%.2lf",ans);
return 0;
}