LA 4327 Parade

动态规划+单调队列

记左上角的十字路口为(1, 1), 右下角的十字路口为 (n + 1, m + 1)

记f[i][j] 表示从第一行任意十字路口出发游行到 (i, j) 的最大收益

可以用前缀和来表示同一行上任意两点之间的欢迎值、距离之和

讨论在同一行间的移动方向得到转移方程:

f[i][j] = max(f[i - 1][j], max(f[i - 1][t] + abs(p[i][j] - p[i][t])) // abs(e[i][j] - e[i][t]) <= k

因为对于任意 (i, j) dis(j, i) <= dis(j, i + 1), 所以考虑用单调队列维护 max(f[i - 1][t] + abs(p[i][j] - p[i][t]) 的值

对于从左往右走:

若 j, k (j < k) 满足 f[i - 1][k] - p[i][k] >= f[i - 1][j] - p[i][j] 那么 k 一定比 j 优

对于从右往左走与之类似,不在讨论

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 105, M = 1e4 + 5;
 5 typedef long long LL;
 6 
 7 int n, m, k, q[M], l, r;
 8 LL f[N][M], e[N][M], p[N][M], ans = 0;
 9 
10 void dp() {
11     ans = 0;
12     for(int i = 1; i <= m; i++) f[0][i] = 0;
13     for(int i = 1; i <= n; i++) {
14         l = r = 1;
15         q[l] = 1;
16         for(int j = 1; j <= m; j++) f[i][j] = f[i - 1][j];
17         for(int j = 2; j <= m; j++) {
18             while(e[i][j] - e[i][q[l]] > k && l <= r) l++;
19             if(l <= r) f[i][j] = max(f[i][j], f[i - 1][q[l]] + p[i][j] - p[i][q[l]]);
20             while(l <= r && f[i - 1][j] - p[i][j] >= f[i - 1][q[r]] - p[i][q[r]]) r--;
21             q[++r] = j; 
22         }
23         l = r = 1;
24         q[l] = m; 
25         for(int j = m - 1; j; j--) {
26             while(e[i][q[l]] - e[i][j] > k && l <= r) l++;
27             if(l <= r) f[i][j] = max(f[i][j], f[i - 1][q[l]] + p[i][q[l]] - p[i][j]);
28             while(l <= r && f[i - 1][j] + p[i][j] >= f[i - 1][q[r]] + p[i][q[r]]) r--;
29             q[++r] = j;
30         }
31     }
32     for(int i = 1; i <= m; i++)
33         ans = max(ans, f[n][i]);
34     cout<<ans<<endl;
35 }
36 
37 int main() {
38     while(cin>>n>>m>>k && n) {
39         n++; m++;
40         memset(p, 0, sizeof(p));
41         memset(e, 0, sizeof(e));
42         memset(f, -0x7f, sizeof(f));
43         for(int i = 1; i <= n; i++) 
44             for(int j = 2; j <= m; j++) {
45                 scanf("%lld", &p[i][j]);
46                 p[i][j] += p[i][j - 1];
47             }
48         for(int i = 1; i <= n; i++) 
49             for(int j = 2; j <= m; j++) {
50                 scanf("%lld", &e[i][j]);
51                 e[i][j] += e[i][j - 1];
52             }
53         dp();
54     }
55     return 0;
56 }
View Code
扫描二维码关注公众号,回复: 9225479 查看本文章

猜你喜欢

转载自www.cnblogs.com/ympc2005/p/12323827.html
LA
今日推荐