题目
一个人从起点出发,要走距离D,
每秒他会持续受到A点伤害(即不是直接在这秒开始或结束统一扣血,是在这1s内均摊的),
初始血量H=0,速度V=0,每秒生命回复R=0(每秒末回复R点生命值,瞬时回血而非持续)。
提升一点血量、速度、生命回复的花费分别为G1、G2、G3。
要求走到终点的过程中,生命值不能小于0(可以等于0),
且提升速度不能超过D,问最小花费是多少。
1 <= D,A <= 500000, 1 <= G1, G2, G3 <= 200
思路来源
https://blog.csdn.net/qq_31759205/article/details/81951609
题解
虽然题面很长,但其实是个很水的题,
首先由速度不能超过D,想到枚举速度1到D,
枚举速度v,从起点到终点的时间t就固定下来了,
在速度上的花费v*G[2]①也确定下来了,
血量应至少为A,否则第一秒就死了,花费为A*G[1]②
剩余的时间为D/v-1,考虑回血和初始血量满足条件两种情形,
回血,只需满足R==A即可,花费为A*G[3]③,
初始血量够,还需血量A*(D/v-1),血量需向上取整,花费为A*(D/v-1)*G[1]③
枚举v,取一个①+②+③的最小值即可,式子可进一步化简
心得
诶,平时跟榜跟习惯了,有的时候丧失自己独立思考的能力了
感觉赛后补题很重要啊,培养自己在很少人做出来的情况下,独立开榜的思维和能力
注意,这种线性规划题取G[1]和G[3]往往具有单增或单减性质,
即最值只可能在两个端界取得,不可能在中间取得
即可化简为形如a+b=定值sum,求z=X*a+Y*b的最值的类型
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
ll D,A,g[4];
ll t,ans;
int main()
{
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
ans=4e18;
scanf("%lld%lld",&D,&A);
for(int i=1;i<=3;++i)
scanf("%lld",&g[i]);
for(ll v=1;v<=D;++v)
ans=min(ans,v*g[2]+min((A*D+v-1)/v*g[1],(g[1]+g[3])*A));
printf("Case #%d: %lld\n",cas,ans);
}
return 0;
}