热身训练4 Article

Article

在这个学期即将结束时,DRD开始写他的最后一篇文章。

DRD使用著名的Macrohard的软件World来写他的文章。
不幸的是,这个软件相当不稳定,它总是崩溃。
DRD需要在他的文章中写N个字符。
他可以在i+0.1的时候按一个键来输入一个字符,其中i是一个等于或大于0的整数。
但是在每一次i-0.1的时候,如果整数i严格大于0,世界可能会以概率p崩溃,DRD就会失去他的工作,所以他可能不得不从他最近保存的文章重新开始。
为了防止重复写,DRD可以在i时间按Ctrl-S来保存他的文件。
由于DRD使用的键盘很奇怪,按Ctrl-S需要按tmp个字符。
如果DRD已经输入了他的全部文章,他必须按Ctrl-S来保存文件。

由于《世界》经常崩溃,现在他正在向他的朋友ATM询问输入文章的最佳策略。
一个策略是以DRD需要按的预期键来衡量的。

请注意,DRD可以以足够快的速度按下一个键。

分析:

加入我们不用“保存”操作,我们可以O(n)的dp求出,写到第i个字符期望需要的打字数。

假如我们要进行k次保存操作,Ans=∑dp[xi] (1<=i<=k,xi表示第i段的长度,∑xi=n)+k*tmp。

对于每段的长度,我们贪心的来说,肯定越平均越好。

于是这道题大致就做完了,最终只需要枚举保存操作的次数即可。

#include<bits/stdc++.h>
using namespace std;
#define re register int
double f[1000005];
int main()
{
    int T;scanf("%d",&T);
    for(re cas=1;cas<=T;++cas)
    {
        int n, x;
        double p, ans=1e16;
        scanf("%d%lf%d",&n,&p,&x);
        memset(f, 0, sizeof(f));
        for(re i=1;i<=n;++i) f[i] = (f[i-1]+1.0) / (1.0-p);
        for(re i=1;i<=n;++i)
        {
            int t = n/i, k = n%i;
            double ret = i * x + k*f[t+1] + (i-k)*f[t];
            ans = min(ans, ret);
        }
        printf("Case #%d: %.6lf\n", cas, ans);
    }
}

 

posted @ 2021-08-18 22:01  kzsn  阅读(56)  评论(0)    收藏  举报