dadadadadka
这是一个动态规划问题。灵梦从第一行出发,每秒钟必须下移一行,同时可以左右移动至多T格。目标是收集尽可能多的P点价值。
解题思路
-
状态定义
定义 f[i][j] 表示到达第 i 行第 j 列时,能获得的最大P点价值总和。 -
状态转移
从第 i-1 行到第 i 行,灵梦可以左右移动至多 T 格,所以:
text
f[i][j] = val[i][j] + max(f[i-1][k]),其中 |j - k| ≤ T
即从上一行的 [j-T, j+T] 范围内取最大值,加上当前格子的价值。
- 优化
如果直接枚举 k,时间复杂度为 O(N * M * T),会超时。
使用单调队列优化:对于每一行,用单调队列维护窗口 [j-T, j+T] 内的最大值,将转移优化到 O(1)。
完整代码
#include<cstdio>
#include<ctype.h>
#include<cstring>
#define int long long
#define max(a,b) a>b?a:b
const int MARX = 4e3+10;
int n, m, k, t, now, ans;
int f[MARX][MARX];
int head, tail;
int q[MARX];
inline int read() {
int fl=1, w=0;
char ch=getchar();
while(!isdigit(ch) && ch!='-') ch=getchar();
if(ch=='-') fl=-1;
while(isdigit(ch)) {
w=w*10+ch-'0';
ch=getchar();
}
return fl*w;
}
void in(int x) {
while(tail >= head && f[now-1][x] > f[now-1][q[tail]])
tail--;
q[++tail] = x;
}
int find(int x) {
if(x + t <= m) in(x + t);
while(q[head] + t < x) head++;
return q[head];
}
signed main() {
n=read(), m=read(), k=read(), t=read();
while(k--) {
int x=read(), y=read(), w=read();
f[x][y] = w;
}
for(now=2; now<=n; now++) {
head=1, tail=0;
for(int i=1; i<=t && i<=m; i++) in(i);
for(int j=1; j<=m; j++) {
f[now][j] += f[now-1][find(j)];
}
}
ans=0;
for(int i=1; i<=m; i++) {
if(f[n][i] > ans) ans = f[n][i];
}
printf("%lld", ans);
return 0;

浙公网安备 33010602011771号