CF1743 E - FTL(线性DP)
E - FTL(线性DP)
题意
现在你有两支激光枪,枪A伤害为\(p_1\),冷却时间为\(t_2\);枪B伤害为\(p_2\),冷却时间为\(t_2\)。敌人的护甲为s,可以抵消每一次攻击中的s点伤害。请问最快造成\(h(h \leqslant 5000)\)伤害的时间是多少。
思路
如果将A和B一起发射,那么将造成\((p_1+p_2-s)\),对于单独的发射,为\(p_i-s\)。那么我们就知道,有时候需要单独发射,有时候需要齐射。易知这是一个动态规划问题。考虑到h比较小,可以设置状态\(f[i]\)为造成i点伤害花费的最小时间。
第一步,我们可以得到一个简单的转移,也就是当前伤害为\(i\)是由上一次单独发射枪A或者枪B的而来的。但是这个情况就没有考虑到齐射的情况,我们现在就需要思考如何转移齐射的情况。枚举伤害是5e3,所以我们还可以通过\(O(n)\)的时间来枚举齐射。由于\(1 \leqslant t_i\),所以我们可以枚举一下让枪A射\(j\)轮,且最后一轮是齐射;以及让枪B射\(j\)轮,且最后一轮为齐射。那么转移方程就已经出来了,再初始化为正无穷,设\(f_0 = 0\),问题可解。
对于齐射的转移,我们可以看做在发动一次齐射之前,两者的策略就是:只要冷却时间一结束,就马上发起攻击。
实现
我们会发现在前几个阶段递推的时候,下标会变负。假设我们的伤害都为5,那么\(f_1,f_2,f_3...\)这几个状态都是第一次独射得来的。所以我们直接将下标与0取一个max就可以了。
#define int long long
const int N = 5005;
int f[N];
int p1, p2, t1, t2;
int h, s;
void solve()
{
cin >> p1 >> t1 >> p2 >> t2;
cin >> h >> s;
memset(f, 0x3f, sizeof f);
f[0] = 0;
for(int i = 1; i <= h; i ++)
{
f[i] = min(f[max(0ll, i - (p1 - s))] + t1, f[max(0ll, i - (p2 - s))] + t2);
for(int j = 1; j <= i; j ++)
{
if(t1 * j >= t2)
{
int dmg = (j - 1) * (p1 - s) + (t1 * j - t2) / t2 * (p2 - s) + (p1 + p2 - s);
f[i] = min(f[i], f[max(0ll, i - dmg)] + t1 * j);
}
if(t2 * j >= t1)
{
int dmg = (j - 1) * (p2 - s) + (t2 * j - t1) / t1 * (p1 - s) + (p1 + p2 - s);
f[i] = min(f[i], f[max(0ll, i - dmg)] + t2 * j);
}
}
}
cout << f[h] << '\n';
}