dadadadadka

这是一个动态规划问题。灵梦从第一行出发,每秒钟必须下移一行,同时可以左右移动至多T格。目标是收集尽可能多的P点价值。

解题思路

  1. 状态定义
    定义 f[i][j] 表示到达第 i 行第 j 列时,能获得的最大P点价值总和。

  2. 状态转移
    从第 i-1 行到第 i 行,灵梦可以左右移动至多 T 格,所以:

text
f[i][j] = val[i][j] + max(f[i-1][k]),其中 |j - k| ≤ T
即从上一行的 [j-T, j+T] 范围内取最大值,加上当前格子的价值。

  1. 优化
    如果直接枚举 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;
posted @ 2026-07-21 23:05  happy0x3F  阅读(10)  评论(0)    收藏  举报