0%

Codeforces Round 1086 (Div. 2)——CF-2208-C. Stamina and Tasks(赛时 AC)(确实,乘法衰减,概率 dp,都是用这个反向居多)

题目大意

题目要求总结:

给定多组测试。每组有 n 个任务,必须按编号从 1n 依次处理。你初始体力为 S=1

对每个任务 i(参数为 c_i, p_i)只有两种选择:

  • 放弃:本任务得分不变,体力不变。

  • 完成:本任务获得 S * c_i 分,然后体力变为S = S * (1 - p_i / 100)

目标是在处理完所有任务后,使总得分最大。

输入规模:多组数据,sum(n) <= 1e5

输出要求:每组输出一个实数最大值,误差满足 1e-6 即可。

样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
Input
2
2
10 0
20 5
3
10 5
10 80
20 5

Output
30.0000000000
29.0000000000

样例解释:

  • 第 1 组:做第 1、2 个任务最优。
    第 1 个得 1*10=10,且 p=0 体力不变;第 2 个得 1*20=20;总分 30

  • 第 2 组:最优是做第 1 个,放弃第 2 个,做第 3 个。
    做完第 1 个后体力 S=1*(1-5/100)=0.95;第 3 个得 0.95*20=19;总分 10+19=29

思路讲解

这道题目,就是主要要注意到,就是我们不难发现,最后一个数,我们肯定是要选的,因为最后一个数对整体的贡献一定是有的,一定是正的。或者,你可以这样想,我们前面先选了一堆数,那么最后一个数一定是要选的,因为选择他,对你的答案一定是增加的,你也不用考虑后续节点的情况,因为他后面也没有东西了

我们说白了,选不选一个数,我们就是怕这个后效性嘛,我们直接反过来,直接对所有选择的后缀进行这个乘法衰减。

但是,再前面的数字,那就不一定了,其对整体的贡献,就是新的答案 ans*(100-p)/100.0+A[i].c,如果说比原来的 ans 还小,那就开摆,否则就算了。

1
2
3
4
5
6
for (ll i=N;i>=1;--i) {
ll c=A[i].c,p=A[i].p;
if (ans*(100-p)/100.0+A[i].c>ans) {
ans=ans*(100-p)/100.0+A[i].c;
}
}

AC代码

AC

https://codeforces.com/contest/2208/submission/366718643

心路历程(WA,TLE,MLE……)