Power收集
题目背景
据说在红雾异变时,博丽灵梦单身前往红魔馆,用十分强硬的手段将事件解决了。
然而当时灵梦在Power达到MAX之前,不具有“上线收点”的能力,所以她想要知道她能收集多少P点,然而这个问题她答不上来,于是她找到了学OI的你。
题目描述
可以把游戏界面理解成一个N行M列的棋盘,有K个格子上有P点,其价值为val(i,j)
初始灵梦可以选择在第一行的任意一个格子出发,每秒她必须下移一格。
灵梦具有一个左右移动的速度T,可以使她每秒向左或右移动至多T格,也可以不移动,并且不能折返。移动可视为瞬间完成,不经过路途上的点,只能获得目标格子的P点。
求最终她能获得的POWER值最大是多少?
输入格式
第一行四个数字,N,M,K,T
接下来K行每行3个数字x,y,v,代表第x行第y列有一个val为v的P点,数据保证一个格子上最多只有1个P点。
输出格式
一个数字
输入输出样例
输入 #1
3 3 4 1 1 1 3 1 2 1 2 2 3 3 3 3
输出 #1
9
说明/提示
对于40%的测试点,1<=N,M,T,K<=200
对于100%的测试点,1<=N,M,T,K<=4000
v<=100,N,M,K,T均为整数
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 6e5 + 10; int n, m, k, t; int w[5006][5006]; int que[5006][6]; int dp[5006][5006]; int main() { scanf("%d%d%d%d", &n, &m, &k, &t); for (register int i = 1, x, y; i <= k; ++i) { scanf("%d%d", &x, &y); scanf("%d", &w[x][y]); } int head = 1, tail = 0; for (register int i = 1; i <= n; ++i) { head = 1, tail = 0; for (register int j = 1; j <= min(m, t); ++j) { while (head <= tail && que[tail][0] <= dp[i - 1][j]) { tail--; } que[++tail][0] = dp[i - 1][j]; que[tail][1] = j; } //printf("debug que[tail][0] = %d\n", que[tail][0]); for (register int j = 1; j <= m; ++j) { if (j + t <= m) { while (head <= tail && que[tail][0] <= dp[i - 1][j + t]) { tail--; } que[++tail][0] = dp[i - 1][j + t]; que[tail][1] = j + t; } while (que[head][1] < j - t) { head++; } dp[i][j] = que[head][0] + w[i][j]; } } int res = 0; for (register int i = 1; i <= m; ++i) { res = max(res, dp[n][i]); } printf("%d\n", res); return 0; }