1426: 收集邮票
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 500 Solved: 413
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
Source
HOMEBack
---------------------------------
这道题一开始有一个非常naive的写法...那是因为我忽略了买一张邮票还要花钱...我还以为求张数心里暗想傻逼入门题... 还是我太naive了...
首先这道题比较难以处理的就是钱. 那么我们所需要知道的实际上当前是买的是第几张(第几张就是多少钱). 那么如果我们要用f[i]表示当前已经收集了i种还需花多少钱才能收集完的话肯定是不够的, 因为转移的时候需要知道当前是买的第几张. 所以另外维护一个数组g[i]表示当已经有i种还需买多少次才能收集完.
首先很明显f[0]就是答案. 假设已经求出g数组, 考虑f数组的转移.
首先对于f[i], 有i/n的几率转移到f[i], 就是说买中了已经收集到的邮票. 那么考虑转移到f[i的代价. ]因为我们知道我们期望还需买g[i]次, 那么当前就是第g[i] + 1次. 那么这次的花费就是g[i] + 1.
那么 转移到f[i]就是 (i /n) * ( f[i] + g[i] + 1).
对于(n - i) / n的几率转移到f[i + 1], 那么同上分析花费就是: ((n - i) / n) * (f[i +1] + g[i + 1] + 1). 综上:
f[i] = (i /n) * ( f[i] + g[i] + 1) +( (n - i) / n) * (f[i +1] + g[i + 1] + 1).
化简之后就是:
f[i] = f[i + 1] + g[i + 1] +( i / (n - i)) * g[i] + n / (n - i) + 1.
对于g数组 g[i] = i / n * g[i] + (n - i) / n * g[i + 1] .
化简得: g[i] = g[i + 1] + n / (n - i);
还有一种用公式推导的办法, 也很有价值看看 :http://www.cnblogs.com/DaD3zZ-Beyonder/p/5904217.html.(超链接出了点问题).
#include<stdio.h>
const int maxn = 10010;
double f[maxn], g[maxn], n;
int main(){
scanf("%lf", &n);
for(int i = n - 1; ~i; --i)
g[i] = g[i + 1] + n / (n - i);
for(int i = n - 1; ~i; --i)
f[i] = f[i + 1] + g[i + 1] + i / (n - i) * g[i] + n / (n - i);
printf("%0.2lf\n", f[0]);
}