持续创作,加速成长!这是我参与「掘金日新计划 · 1 月更文挑战」的第19天,点击查看活动详情
【Codeforces】Educational Codeforces Round 137 - E. FTL
题目链接
题目大意
Monocarp 在他的飞船上安装了两台激光炮。激光炮 1 经过 的时间充能后可以发射,威力为 ;激光炮 2 经过 的时间充能后可以发射,威力为 。
当一台激光炮充能完毕后,Monocarp 可以发射它,也可以等待另一台激光炮充能完毕后同时发射两台激光炮。
敌方飞船具有 耐久度和 护盾。当 Monocarp 仅发射激光炮 时,敌方飞船会受到 点伤害。(即它的耐久度减少 )。如果同时发射两台激光炮,敌方飞船会受到 点伤害。敌方飞船在其耐久度变为 0 或更低时被视为已摧毁。
最初,两个激光炮充能进度为 0。
Monocarp 摧毁敌方飞船所需的最短时间是多少?
。
思路
令 表示造成 点伤害需要的最短时间。
先考虑恰好发射了 枚激光炮 1 造成的伤害,我们花费的时间 :
- 如果只单独发射两种激光炮,此时可以发射 枚激光炮 2。造成的伤害 。
- 我们显然可以暂时不发送第 枚激光炮,等到第 枚激光炮充能完毕后将二者同时发送,使得造成的伤害增加 。
- 用 更新造成不超过 点伤害所需要的时间。
同样的,我们可以处理出恰好发射了 枚激光炮 2 造成的伤害,并更新 dp 数组。
但是我们发现使用上述方法更新出的 dp 数组仅包含只使用了一次组合攻击的信息。该怎样求出使用了若干次组合攻击造成 点伤害需要的最短时间呢?
容易发现,当我们同时发射了两种激光炮,两个激光炮的充能进度都会归 0,与第 0 时刻的情况相同。所以我们可以用造成 点伤害需要的时间和造成 点伤害需要的时间之和来更新 造成 点伤害需要的世界。即 。
代码
#include <bits/stdc++.h>
using namespace std;
using LL=long long;
LL t1,t2,dp[5001],t,p1,p2,s,h,p;
int solve()
{
cin>>p1>>t1;
cin>>p2>>t2;
cin>>h>>s;
dp[0]=0;
for (int i=1;i<=h;++i) dp[i]=1ll<<60;
for (int i=1;;++i)
{
t=i*t1;
p=i*p1-i*s+t/t2*p2-t/t2*s;
if (t/t2) p+=s;
for (int j=min(p,h);dp[j]>t;--j) dp[j]=t;
if (p>h) break;
}
for (int i=1;;++i)
{
t=i*t2;
p=i*p2-i*s+t/t1*p1-t/t1*s;
if (t/t1) p+=s;
for (int j=min(p,h);dp[j]>t;--j) dp[j]=t;
if (p>h) break;
}
for (int i=1;i<=h;++i)
for (int k=1;k<=i-k;++k) dp[i]=min(dp[i],dp[k]+dp[i-k]);
printf("%lld\n",dp[h]);
return 0;
}
int main()
{
solve();
return 0;
}