单调队列--P3800 Power收集

*传送

对于一个$n \times m$的矩形,我们只要对每一行求滑动窗口,当前位置的最大价值就是他上一行的滑动窗口(点击查看解释)+当前位置的价值。因为当前位置左上T个位置,会被他左边T个位置的点更新到,所以我们只需要算一边就好。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxn= 4005;
 6 int N, M, K, T, val[maxn][maxn], f[maxn][maxn], g[maxn];
 7 int head, tail, q[maxn];
 8 int main() {
 9     cin >> N >> M >> K >> T;
10     for (register int i = 1; i <= K; ++i) {
11         int x, y, z;
12         scanf("%d%d%d", &x, &y, &z);
13         val[x][y] = z;
14     }
15     memset(f, -0x3f, sizeof(f));
16     for (int i = 1; i <= M; ++i) 
17         f[1][i] = val[1][i];
18     tail = 0, head = 1;
19     for (register int i = 2; i <= N; ++i) {
20         q[head = 0] = q[tail = 1] = 0;
21         for (register int j = 1; j <= M; ++j) {            
22             while (head <= tail && j - q[head]>T) head++;
23             while (head <= tail && f[i - 1][q[tail]] <= f[i - 1][j]) tail--;
24             q[++tail] = j, g[j] = f[i - 1][q[head]];
25         }
26           for (register int j = 1; j <= M; ++j) {
27               int l = j, r = min(j + T, M);
28               f[i][j] = max(g[l], g[r]) + val[i][j];
29         }
30     }
31     int Ans = -2e9;
32     for (int i = 1; i <= M; ++i) 
33         Ans = max(Ans, f[N][i]);
34     printf("%d\n", Ans);
35     return 0;
36 }

 

posted @ 2020-03-14 16:36  小又又  阅读(128)  评论(0编辑  收藏  举报