POJ 3926 Parade 单调队列优化DP

来源:http://poj.org/problem?id=3926

题意:行n <= 100, 列m <= 10000,类似于数字三角形,一个人要从底下往上走,每层中可以左右走,但选定方向不能回头(向左不能再向右),每经过一段获得该段的一个值,并走了该段的距离,在同一层走的距离不能超过k。问走到最顶头,获得的总值最大是多少。

分析:dp[i][j]表示走到第i行第j列,获得的值最大为多少。则dp[i][j] = max(dp[i+1][p] + sum(p to j)),sum(p to j)表示第i行从第p列到第j列的值的和,同时p需要满足abs(p-j) <= k。前缀和处理sum,枚举i,j,p,这样是o(nm^2)的复杂度,超时。

如果我们只考虑从左往右走,那么就是类似求有长度上限的最大子段和的模型了。sum(k)表示第i行前k列的前缀和,改写转移方程 dp[i][j] = max(dp[i+1][p] + sum(j) - sum(p)) = max(dp[i+1][p] - sum(p)) + sum(j),这下很清楚了,前一项就可以用单调队列来维护,使得状态转移的复杂度降到均摊o(1)。然后从右往左走再做一遍就可以了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5
 6 int n, m, k;
 7 int a[120][10100], b[120][10100], dp[120][10100];
 8 struct que{
 9     int v, d;
10 } q[10100];
11 inline int in(){
12     char ch = getchar();
13     while((ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘) ch = getchar();
14     bool flag = false;
15     if (ch == ‘-‘){
16         flag = true;
17         ch = getchar();
18     }
19     int ans = 0;
20     while(ch >= ‘0‘ && ch <= ‘9‘){
21         ans = ans*10 + ch-‘0‘;
22         ch = getchar();
23     }
24     if (flag) return -ans;
25     return ans;
26 }
27 int main()
28 {
29     while(scanf("%d%d%d", &n, &m, &k) && (n+m+k))
30     {
31         for (int i = 0; i <= n; i++)
32             for (int j = 0; j < m; j++)
33                 a[i][j] = in();
34         for (int i = 0; i <= n; i++)
35             for (int j = 0; j < m; j++)
36                 b[i][j] = in();
37         for (int j = 0; j <= m; j++)
38             dp[n+1][j] = 0;
39         for (int i = n; i >= 0; i--){
40             int sum, head, tail, dis;
41             sum = head = tail = dis = 0;
42             dp[i][0] = dp[i+1][0];
43             q[tail].v = dp[i][0];
44             q[tail++].d = 0;
45             for (int j = 1; j <= m; j++){
46                 sum += a[i][j-1];
47                 dis += b[i][j-1];
48                 while(head < tail && dis - q[head].d > k) head ++;
49                 while(head < tail && q[tail-1].v <= dp[i+1][j] - sum) tail --;
50                 q[tail].d = dis;
51                 q[tail++].v = dp[i+1][j] - sum;
52                 dp[i][j] = q[head].v + sum;
53             }
54             sum = head = tail = dis = 0;
55             q[tail].v = dp[i+1][m];
56             q[tail++].d = 0;
57             for (int j = m-1; j >= 0; j--){
58                 sum += a[i][j];
59                 dis += b[i][j];
60                 while(head < tail && dis - q[head].d > k) head ++;
61                 while(head < tail && q[tail-1].v <= dp[i+1][j] - sum) tail --;
62                 q[tail].d = dis;
63                 q[tail++].v = dp[i+1][j] - sum;
64                 if (q[head].v + sum > dp[i][j]) dp[i][j] = q[head].v + sum;
65             }
66         }
67         int ans = 0;
68         for (int i = 0; i <= m; i++)
69             if (dp[0][i] > ans) ans = dp[0][i];
70         printf("%d\n", ans);
71     }
72     return 0;
73 }

POJ 3926 Parade 单调队列优化DP

时间: 2024-08-27 04:02:21

POJ 3926 Parade 单调队列优化DP的相关文章

Parade(单调队列优化dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 902    Accepted Submission(s): 396 Problem Description Panagola, The Lord of city F lik

POJ 1821 Fence(单调队列优化DP)

题解 以前做过很多单调队列优化DP的题. 这个题有一点不同是对于有的状态可以转移,有的状态不能转移. 然后一堆边界和注意点.导致写起来就很难受. 然后状态也比较难定义. dp[i][j]代表前i个人涂完前j个位置的最大收益. 然后转移考虑 第i个人可以不刷.dp[i][j]=dp[i-1][j]; 第j个木板可以不刷dp[i][j]=dp[i][j-1]; 然后当c[i].s<=j<=s[i]+l[i]-1时 dp[i][j]=p[i]*j+max(dp[i-1][k]-p[i]*k)其中j-

POJ 3017 Cut the Sequence (单调队列优化DP)

POJ 3017 Cut the Sequence (单调队列优化DP) ACM 题目地址: POJ 3017 Cut the Sequence 题意: 将一个由N个数组成的序列划分成若干段,要求每段数字的和不超过M,求[每段的最大值]的和 的最小的划分方法,输出这个最小的和. 分析: 方程是:dp[i] = min(dp[j]+maxsum[j+1][i]) 但复杂度n*n太高,需要优化. 可以用单调队列+BST优化,其实只需要维护每一段的最大值. 看了这篇题解的:http://blog.cs

HDU 4122 Alice&#39;s mooncake shop 单调队列优化dp

Alice's mooncake shop Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4122 Description The Mid-Autumn Festival, also known as the Moon Festival or Zhongqiu Festival is a popular harvest festival celebrated by Ch

Tyvj1305最大子序和(单调队列优化dp)

描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入格式 第一行两个数n,m第二行有n个数,要求在n个数找到最大子序和 输出格式 一个数,数出他们的最大子序和 测试样例1 输入 6 4 1 -3 5 1 -2 3 输出 7 备注 数据范围:100%满足n,m<=300000 是不超过m,不是选m个!!!!! /* 单调队列优化dp 单调队列维护的是前

bzoj1855: [Scoi2010]股票交易--单调队列优化DP

单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w-1][k]+k*Ap[i]的单调性即可 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2010; 6 int

1855: [Scoi2010]股票交易[单调队列优化DP]

1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status][Discuss] Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=

BZOJ 1855 股票交易(单调队列优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每 个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BS

【单调队列优化dp】uestc 594 我要长高

http://acm.uestc.edu.cn/#/problem/show/594 [AC] 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=5e4+2; 5 const int inf=0x3f3f3f3f; 6 int n,c; 7 int cur; 8 int dp[2][maxn]; 9 int q[maxn]; 10 int main() 11 { 1