HDU 5236 Article 期望

题意:

你现在要打\(n\)个字符,但是程序随时可能会崩溃。
你可以在恰当的时机按下 \(Ctrl-S\)键,崩溃后,会从最后一次保存的情况继续开始打字。
具体是这样的:

  • 在每个第\(i-0.1s(i>0)\)的时候,程序崩溃的概率为\(p\)
  • 在每个第\(is(i \geq 0)\)的时候,你可以一口气按下\(x\)个键来存盘
  • 在每个第\(i+0.1s(i \geq 0)\)的时候,你可以按下一个键来打字

求采取最优策略下,打完这\(n\)个字符,并且最后存盘,总按键次数的期望。

分析:

先不考虑可以存盘的情况,设\(d(i)\)为打印\(i\)个字符按键次数的期望。
有递推公式:\(d(i)=d(i-1)+1+p \cdot d(i)\)
当你打印出前\(i-1\)个字符,刚刚打完第\(i\)个的时候:

  • 有概率\(p\)会崩掉,这时候要重新开始,还需要的按键数的期望为\(d(i)\)
  • 有概率\(1-p\)没崩,打印完成了

化简一下得到:\(d(i)=\frac{1}{1-p}d(i-1)+\frac{1}{1-p}\)

然后再考虑存盘的情况,我们枚举存了\(x\)次盘,也就是把这\(n\)个字符分为\(x\)段,每打完一段就存一次盘。
由于\(\frac{1}{1-p}>1\),可以看出\(d(n)\)是指数型增长的,所以就尽可能均匀地把\(n\)个字符分成\(x\)段。
或者也可以求一下\(d(n)\)的通项公式为:\(d(n)=\frac{1}{p(1-p)^n}-\frac{1}{p}\)来验证。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 10;
const double INF = 1e20;
double d[maxn];

int main()
{
    int T; scanf("%d", &T);
    for(int kase = 1; kase <= T; kase++) {
        int n, x; double p;
        scanf("%d%lf%d", &n, &p, &x);
        
        d[0] = 0;
        for(int i = 1; i <= n; i++) d[i] = (d[i - 1] + 1.0) / (1.0 - p);

        double ans = INF;
        for(int i = 1; i <= n; i++) {
            int k = n / i, r = n % i;
            ans = min(ans, r*d[k+1] + (i-r)*d[k] + i*x);
        }

        printf("Case #%d: %.6f\n", kase, ans);
    }

    return 0;
}
posted @ 2015-11-06 17:06  AOQNRMGYXLMV  阅读(290)  评论(0编辑  收藏  举报