Blackops

初心易得,始终难守

0%

哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-低年级组)J 长跑(DP+滚动数组)

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述
小明参加了长跑比赛,只要到达终点就算小明成功了,长跑总路径长度为L,赛道是直线的,我们可以视为最左边为起点,最右边为终点。沿途上共计N个补给节点,补给节点可以供给选手休息,补充体力,直接可以将体力补满。第i个补给节点位于位子Pi(从左往右第Pi个单位位子),想要在这里补充体力需要花费Ci个硬币。
小明的体力上限为Maxn,初始的时候视为小明的体力是满额的,每消耗一单位体力,能够跑一单位距离。当小明没有体力的时候,他会趴在地上不动(如果当前位子上有补给节点,他仍然可以花费对应硬币补充能量)
小明初始的时候教练会给他S个硬币,小明想知道自己能否成功跑到终点。
输入描述:
本题包含多组数据,每组数据包含N+1行。
第一行输入四个个数字N,L,Maxn,S
接下来N行,每行输入两个数字,Pi,Ci
数据范围:
每个点上边可能有多个补给站(毕竟要货比三家啊);
0<=N<=2000
0<=L<=20000
0<=Maxn<=20000
0<=S<=2000
1<=Pi<=N
1000<=Ci<=3000
输出描述:
每组数据输出一行,如果小明能够跑到终点,那么输出Yes,否则输出No
示例1
输入

1 1000 500 2000
500 2000
1 1000 500 2000
500 3000
输出

Yes
No

题目链接:J.长跑
根据题目的范围发现似乎可以用$DP$写啊,$dp[i][j]$表示当前跑的长度为$i$,剩余硬币数为$j$,所能保存的最大体力值,那么转移方程就是:

然后直接看$dp[l][\;]$这一行是否有一个位置体力大于等于$0$即可。
咦,发现样例可过,难道$DP$蒟蒻选手这样就可以轻松$AC$了吗(滑稽,显然没有这么容易$AC$),可惜$memset$爆内存了,于是又回去把$cost$数组改成了$short$,还是爆内存,再看转移方程发现卧槽这不是明显滚动数组吗,果断修改修改就过了233(真是ZZ啊)
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define fin(name) freopen(name,"r",stdin)
#define fout(name) freopen(name,"w",stdout)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 2005;
const int M = 20005;
int dp[2][N];
short cost[M];

int main(void)
{
int n, l, mn, s, i, j;
while (~scanf("%d%d%d%d", &n, &l, &mn, &s))
{
for (int i = 0; i < 2; ++i)
for (int j = 0; j <= s; ++j)
dp[i][j] = -1;
for (int i = 0; i < N; ++i)
cost[i] = 0;
for (i = 0; i < n; ++i)
{
int p, c;
scanf("%d%d", &p, &c);
if (!cost[p] || cost[p] > c)
cost[p] = c;
}
int nxt = 1, pre = 0;
dp[pre][s] = mn;
for (i = 0; i < l; ++i)
{
for (j = 0; j <= s; ++j)
dp[nxt][j] = -1;
if (cost[i + 1])
{
for (j = 0; j <= s; ++j)
{
if (dp[pre][j] >= 1)
dp[nxt][j] = max(dp[nxt][j], dp[pre][j] - 1);
if (j >= cost[i + 1] && dp[pre][j] >= 1)
dp[nxt][j - cost[i + 1]] = mn;
}
}
else
{
for (j = 0; j <= s; ++j)
if (dp[pre][j] >= 1)
dp[nxt][j] = max(dp[nxt][j], dp[pre][j] - 1);
}
swap(nxt, pre);
}
int ans = -1;
for (i = 0; i <= s; ++i)
ans = max(ans, dp[pre][i]);
puts(ans >= 0 ? "Yes" : "No");
}
return 0;
}