线上OJ:
一本通:1940:【07NOIP普及组】守望者的逃离 (opens in a new tab)
AcWing:431. 守望者的逃离 (opens in a new tab)
洛谷:P1095 [NOIP2007 普及组] 守望者的逃离 (opens in a new tab)
核心思想:
1、闪烁耗费1秒,可以增加距离60米,但是恢复10点魔法值还需要2.5秒,所以闪烁的平均速度为 60m/3.5s = 17.14m/s > 跑步的速度17m/s。所以在时间充足的情况下,闪烁比跑步距离更远。
2、但是如果最后剩余的时间不足以支持一次闪烁,则跑步能增加距离。
3、所以,先按照最快的闪烁,计算每一秒钟能出现的位置(闪烁的秒,位置+60;不闪烁的秒,位置不变);最后用跑步来修正每一次等待过程中的距离(等待的秒,可以用跑步+17来更新距离)
动态规划
#include <bits/stdc++.h>
using namespace std;
int m, s, t, dp[300005];
// 恢复10点需要2.5秒,闪烁需要1秒,所以闪烁的平均速度为 60/3.5 = 17.14m/s > 跑步的速度17m/s
// 所以在时间充足的情况下,闪烁比跑步距离更远。
// 先按照最快的闪烁,计算每一秒钟可能出现的位置;最后用跑步来修正每一次等待过程中的距离
int main()
{
scanf("%d %d %d", &m, &s, &t);
for(int i = 1; i <= t; i++)
{
if(m >= 10)
{
dp[i] = dp[i-1]+60; // 如果魔法值够,则跳跃60米
m -= 10;
}
else // 如果魔法值不够,则原地等待,恢复魔法值
{
dp[i] = dp[i-1];
m += 4;
}
}
for(int i = 1; i <= t; i++)
{
dp[i] = max(dp[i], dp[i-1] + 17); // 对于等待的秒,用跑步来修正每一次等待过程中的距离
if(dp[i] >= s)
{
printf("Yes\n%d", i);
return 0;
}
}
printf("No\n%d", dp[t]); // 如果跑不完,则输出最后t时刻的距离即可
return 0;
}