1915 -- 【模拟试题】天堂的馈赠
Description
【题目背景】:
小杉找到了做棉花糖的最优方案,想去摘云朵,可是摔死了……
他来到了天堂。
天堂当然是很大的,也是很缭乱的。
小杉看到一块路标,写着“天堂的馈赠”。
【问题描述】:
考虑到小杉刚死没多久,为了安抚他受创的心灵和思恋的感情,
天堂派出一个天使给小杉送礼,但IQ不够高的小杉可不能够拿到好礼物。馈赠在天堂门口进行。天使站在云端,往下扔礼物。
天堂之门的宽度为W格(按1..W编号),高度为0格,云端的高度为H格,小杉只能站在格子里。
开始时(第0秒),小杉站在天堂之门的第P格。
馈赠开始后,天使会在某些时刻从云端的某格扔礼物下来,礼物下落的速度(格/秒)是不一样的。
小杉左右移动去接礼物(每秒可以移动1格或不移动)。
礼物之间的价值当然是不一样的,小杉事先知道了每个礼物的价值。
当礼物在某一秒末恰好到达小杉所在的格子中,小杉就接到了这个礼物。
小杉想知道,他最多可以拿到价值为多少的礼物。
而且,由于礼物下落的速度有些可以很……,小杉还想知道是不是有些礼物他怎么样也拿不到。
Input
第一行有四个数W,P,H,N(1<=P<=W<=500),(1<=H<=500),(0<=N<=3000)
接下来N行,每行四个数t,r,v,s(0<=t<=1500),(1<=r<=W),(1<=v<=H),(|s|<=1e5)表示天使在t时刻,云端的第r格,以v格/秒的速度扔下价值s的礼物
输入均为正整数;
10%的数据W<=100,H<=100,N<=200
Output
输出两行。
第一行仅有一个整数,表示小杉最多能拿到价值多少的礼物。
第二行也仅有一个整数,表示小杉不可能拿到的礼物总价值多少。
Sample Input
1 1 1 1
1 1 1 1
Sample Output
1
0
Hint
注意:当礼物在某一秒末 恰好 到达小杉所在的格子中,小杉才能接到这个礼物。
这道题目显然是一个dp,而且方程也很好想。
f[i][j]表示在i时刻和j位置所取到的最大值,那么我们可以得到方程为f[i][j]=max(f[i-1][j],f[i-1][j-1],f[i-1][j+1])+w[i][j];
其中w[i][j]表示i时刻j位置可以接到的价值。
那么我们只要预处理出w[i][j]就可以了。
但是有一些细节是需要注意的,比如说:
- 当礼物在某一秒末 恰好 到达小杉所在的格子中,小杉才能接到这个礼物。 注意恰好。不在某一秒末的我们肯定是拿不到的
- 还有拿不到的就是在一开始我们直接前往也无法拿到的。
- 另外需要注意的是,某个礼物的价值可能是负的,那么f数组一定要赋-inf,否则要出事
代码还是比较简单的:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define inf 0x3fffffff
using namespace std;
int w,p,h,n,t,r,v,s,ans2=0,ans=0,T,f[3005][3005],g[3005][3005];
int main(){
cin>>w>>p>>h>>n;
for(int i=1;i<=n;i++)
{
cin>>t>>r>>v>>s;
if(h%v==0)t+=h/v;
else
{
ans2+=s;
continue;
}
T=max(T,t);
g[t][r]=s;
if(abs(p-r)>t)
ans2+=s;
}
for(int i=0;i<=T;i++)
for(int j=0;j<=w+1;j++)
f[i][j]=-inf;
f[0][p]=0;
for(int i=1;i<=T;i++)
for(int j=1;j<=w;j++)
{
if(f[i-1][j]!=-inf)f[i][j]=f[i-1][j]+g[i][j];
if(f[i-1][j-1]!=-inf)f[i][j]=max(f[i][j],f[i-1][j-1]+g[i][j]);
if(f[i-1][j+1]!=-inf)f[i][j]=max(f[i][j],f[i-1][j+1]+g[i][j]);
ans=max(ans,f[i][j]);
}
cout<<ans<<"\n"<<ans2;
return 0;
}