线上OJ:
核心思想:
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];
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;
}
解法二、模拟
本质和动态规划一样,因为在魔法充足的那一秒,一定是闪烁远;其他时刻一定是跑步的距离更远。
我们假设有两个人,a只负责闪烁来更新魔法充足时刻的最远距离,b负责在上一秒的最远距离 + 跑步来更新其他秒的最远距离。
#include <bits/stdc++.h>
using namespace std;
int m, s, t, a = 0, b = 0; // a记录纯闪烁的最远距离,b记录闪烁+跑步的最远距离
// 模拟
int main()
{
scanf("%d %d %d", &m, &s, &t);
for(int i = 1; i <= t; i++)
{
// a只负责闪烁,来更新魔法充足时刻的最远距离
if(m >= 10) // 如果魔法值够
{
a += 60; // 则跳跃60米
m -= 10; // 魔法值减少 10
}
else // 如果魔法值不够
m += 4; // 魔法值恢复 4
// b负责在上一秒的最远距离 + 跑步来更新每一秒的最远距离
b = max(a, b + 17); // 更新最大的距离
if(b >= s)
{
printf("Yes\n%d", i);
return 0;
}
}
printf("No\n%d", b);
return 0;
}