DP练习
链接:https://ac.nowcoder.com/acm/contest/303/L
来源:牛客网
题目描述
tokitsukaze玩到了星际争霸2(StarCraftⅡ)自由之翼的最后一关战役:背水一战(The Last Stand)。
雷诺(Raynor)费劲千辛万苦终于找到了刀锋女王凯瑞甘(Kerrigan),这时候雷诺收集齐了塞尔纳加上古神器。上古神器组装后可以净化被异虫感染的人类。
刀锋女王一开始位于坐标原点,她的初始生命为h,她要进攻位于m处的人类基地。
在进攻的过程中刀锋女王会选择触发一些事件来强化自身,但是因为受到塞尔纳加上古神器的影响,这些事件发生了反转,所以不一定都会给刀锋女王带来强化。
刀锋女王在进攻的过程中会路过n个事件的触发地,其中第i个事件的触发地点为pos[i]。当触发这个事件时,会立刻将刀锋女王的生命值变为H+val[i],H为触发事件时刀锋女王的生命值,注意val[i]的值可能为正也可能为负。触发这个事件的同时,还会给刀锋女王添加一个buff。
为了简化问题,我们认为刀锋女王身上最多只能存在一个buff,也就是后来的buff会覆盖掉之前的buff效果,该buff会持续的改变刀锋女王的生命值,当刀锋女王身上存在buff时,她每往前走一个单位,她的生命值都会变为H+delta[i],H为刀锋女王往前走一个单位前的生命值,注意delta[i]可能为正值,也可能为负值。我们认为一开始刀锋女王身上不具有任何的buff效果。
刀锋女王在路过某个事件的触发地时,她可以选择触发这个事件或者跳过不触发这个事件。不过聪明的刀锋女王总是会选择最优策略,这使她到达人族基地时拥有最多的生命值。
当刀锋女王的生命值小于等于0时,她就会死亡,在保证刀锋女王必须存活的条件下。她到达人族基地时的最大生命值是多少?(假设她的生命值上限无限大的前提下)
输入描述:
第一行输入一个正整数T(1≤T≤30),表示有T组数据。 对于每组案例: 第一行输入三个正整数n,m,h(1≤n≤1000,1≤m≤10^9,1≤h≤10^9)分别表示有n个事件的触发地,刀锋女王要进攻位于m处的人族基地,刀锋女王的初始生命h。 接下来n行每行输入三个正整数pos[i],val[i],delta[i](1≤pos[i]<m ,-10^9≤val[i],delta[i]≤10^9),分别表示第i个事件的触发地为pos[i],如果刀锋女王触发该事件的话,会立刻改变她的生命val[i]点,并且会改变自身buff的状态,之后每往前走一步都会改变她的生命值delta[i]点。 输入保证这n个事件的触发地pos[i]是按照递增顺序输入的,并且pos[i]互不相同。
输出描述:
对于每组数据,请输出一行一个正整数表示刀锋女王在选择最优策略的情况下到达人族基地时自身生命的最大值。
示例1
输入
4 3 5 1 1 -1 100000 2 200 -100 3 -100 2 4 10 1 1 -1 100 2 50 -10 4 -15 3 5 -20 5 4 100 1 1 -1 100 2 50 -10 4 -15 3 5 -20 5 1 1000000000 1 1 900000000 -1
输出
5 34 476 1
说明
第一组样例: 当刀锋女王走到1位置时如果选择触发事件就会立刻失去1点生命而导致死亡,所以她不能触发事件1。 之后刀锋女王走到位置2,她选择触发事件,她先获得200点生命值,所以当前生命值变为201,并且身上获得了一个每走一步生命减少100点的debuff。 刀锋女王走到位置3时由于debuff的效果生命减少100点变为101,之后她选择触发位置3上的事件,生命值先减少100点变为1,并且身上获得了一个每走一步生命值增加2的buff效果,并且该效果覆盖掉了之前的debuff。 刀锋女王从位置3走到位置4,触发一次buff效果,当前生命变为3。 刀锋女王从位置4走到位置5,再次触发buff效果,当前生命变为5。
***************************************
题很长,从(他可以在每个点选择触发和不触发BUFF)得知需用动态规划做
思路就是遍历每个点的前面的点,看内个点触发后走到该点最优,一层一层走下来,最后dp[n+]即保存最大血量;
注意 每个数组的边界处理
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1005;
typedef long long ll;
int pos[maxn];
int val[maxn];
ll dp[maxn];//当前血量
int delta[maxn];
int main(){
int t;
cin>>t;
while(t--){
int n,m,h;
cin>>n>>m>>h;
for(int i=1;i<=n;i++){
cin>>pos[i]>>val[i]>>delta[i];
}
//预处理边界
dp[0]=h;
val[n+1]=0;
delta[n+1]=0;
val[0]=0;
delta[0]=0;
pos[n+1]=m;
///
for(int i=1;i<=n+1;i++){
dp[i]=h+val[i];//先每次都触发
for(int j=0;j<i;j++){//遍历i点之前内个点触发后到该点的血量最大
if(dp[j]>0){//之前内个点血量大于0
dp[i]=max(dp[i],dp[j]+delta[j]*(pos[i]-pos[j])+val[i]);
}
}
}
cout<<dp[n+1]<<endl;
}
return 0;
}