HDU 4374 One hundred layer [单调队列优化DP]

  N层楼,每层M个有分数的格子,一开始在第一层的S点,每层最多不能连续走T个就必须下楼,求到达最底层能获得的最大分数。

  经典的单调队列优化问题,用A[i][j]表示前缀和,now表示当前层,pre表示上一层,可以得到以下递推式:

  当前层从左向右走,d[now][i]=max(d[pre][j]+A[now][i]-A[now][j-1]) = max((d[pre][j]-A[now][j-1])+A[now][i]) (j<=i)

  当前层从右向左走,d[now][i]=max(d[pre][j]+A[now][j]-A[now][i-1]) = max((d[pre][j]+A[now][j])-A[now][i-1]) (j>i)

  括号中的项为单调队列中的比较值,然后d[now][i]取从左和从右走的最大值即可。

  

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 #define INF 0x3f3f3f3f
 6 using namespace std;
 7 int n, m, x, tt;
 8 int mz[105][10005];
 9 int d[10005], t[10005];
10 int q[10005], front, rear;
11 int main(){
12     //freopen("test.in","r",stdin);
13     while (scanf("%d%d%d%d", &n, &m, &x, &tt) != EOF) {
14         for (int i = 1; i <= n; i++)
15             for (int j = 1; j <= m; j++)
16                 scanf("%d", &mz[i][j]), mz[i][j] += mz[i][j-1];
17         for (int i = 1; i <= m; i++) {
18             if (abs(i-x) > tt) d[i] = -INF;
19             else d[i] = x>i ? mz[1][x] - mz[1][i-1] : mz[1][i] - mz[1][x-1];
20         }
21         for (int i = 2; i <= n; i++) {
22             front = rear = 0;
23             for (int j = 1; j <= m; j++) t[j] = d[j] + mz[i][j] - mz[i][j-1];
24             for (int j = 1; j <= m; j++) {
25                 while (front < rear && j - q[front] > tt) front++;
26                 if (front < rear) t[j] = max(t[j], d[q[front]] + mz[i][j] - mz[i][q[front]-1]);
27                 while (front < rear && d[q[rear-1]] - mz[i][q[rear-1]-1] < d[j] - mz[i][j-1]) --rear;
28                 q[rear++] = j;
29             }
30             front = rear = 0;
31             for (int j = m; j >= 1; j--) {
32                 while (front < rear && q[front] - j > tt) front++;
33                 if (front < rear) t[j] = max(t[j], d[q[front]] + mz[i][q[front]] - mz[i][j-1]);
34                 while (front <rear && d[q[rear-1]] + mz[i][q[rear-1]]< d[j] + mz[i][j]) --rear;
35                 q[rear++] = j;
36             }
37             for (int j = 1; j <= m; j++) d[j] = t[j];
38         }
39         int ans = 0;
40         for (int i = 1; i <= m; i++) ans = max(ans, d[i]);
41         printf("%d\n", ans);
42     }
43     return 0;
44 }
原文地址:https://www.cnblogs.com/swm8023/p/2717883.html