LUOGU 1984: [SDOI2008]烧水问题 数论递推
Posted g-hsm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LUOGU 1984: [SDOI2008]烧水问题 数论递推相关的知识,希望对你有一定的参考价值。
title
Description:
把总质量为 1 kg 的水分装在 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 杯水都至少被烧开一遍所需的总能量最少,\(1\leqslant n\leqslant 3000000\)。
analysis
一看数论题目,哈,达标找规律啦。
水 | 能量 |
---|---|
1 | \(f[1]=420000\) |
2 | \(f[2]=f[1]*\frac34=f[1]*\frac(2*2-1)(2*2)=315000\) |
3 | \(f[3]=f[2]*\frac56=f[2]*\frac(2*3-1)(2*3)=262500\) |
... | ... |
\(n\) | \(f[n]=f[n-1]*\frac(2*n-1)(2*n)\) |
所以递推公式就是:
\[
f[n]=f[n-1]*\frac(2*n-1)(2*n)
\]
至于证明,不会(逃。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e6+10;
char buf[1<<15],*fs,*ft;
inline char getc() return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++;
template<typename T>inline void read(T &x)
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
double f[maxn];
int main()
int n;read(n);
f[1]=420000.00;
for (int i=2; i<=n; ++i) f[i]=f[i-1]*(2*i-1)/(i<<1);
printf("%.2f\n",f[n]);
return 0;
以上是关于LUOGU 1984: [SDOI2008]烧水问题 数论递推的主要内容,如果未能解决你的问题,请参考以下文章