POJ 3926 Parade 单调队列优化DP
2014-07-31 10:45
477 查看
来源: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)。然后从右往左走再做一遍就可以了。
题意:行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)。然后从右往左走再做一遍就可以了。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n, m, k; int a[120][10100], b[120][10100], dp[120][10100]; struct que{ int v, d; } q[10100]; inline int in(){ char ch = getchar(); while((ch < '0' || ch > '9') && ch != '-') ch = getchar(); bool flag = false; if (ch == '-'){ flag = true; ch = getchar(); } int ans = 0; while(ch >= '0' && ch <= '9'){ ans = ans*10 + ch-'0'; ch = getchar(); } if (flag) return -ans; return ans; } int main() { while(scanf("%d%d%d", &n, &m, &k) && (n+m+k)) { for (int i = 0; i <= n; i++) for (int j = 0; j < m; j++) a[i][j] = in(); for (int i = 0; i <= n; i++) for (int j = 0; j < m; j++) b[i][j] = in(); for (int j = 0; j <= m; j++) dp[n+1][j] = 0; for (int i = n; i >= 0; i--){ int sum, head, tail, dis; sum = head = tail = dis = 0; dp[i][0] = dp[i+1][0]; q[tail].v = dp[i][0]; q[tail++].d = 0; for (int j = 1; j <= m; j++){ sum += a[i][j-1]; dis += b[i][j-1]; while(head < tail && dis - q[head].d > k) head ++; while(head < tail && q[tail-1].v <= dp[i+1][j] - sum) tail --; q[tail].d = dis; q[tail++].v = dp[i+1][j] - sum; dp[i][j] = q[head].v + sum; } sum = head = tail = dis = 0; q[tail].v = dp[i+1][m]; q[tail++].d = 0; for (int j = m-1; j >= 0; j--){ sum += a[i][j]; dis += b[i][j]; while(head < tail && dis - q[head].d > k) head ++; while(head < tail && q[tail-1].v <= dp[i+1][j] - sum) tail --; q[tail].d = dis; q[tail++].v = dp[i+1][j] - sum; if (q[head].v + sum > dp[i][j]) dp[i][j] = q[head].v + sum; } } int ans = 0; for (int i = 0; i <= m; i++) if (dp[0][i] > ans) ans = dp[0][i]; printf("%d\n", ans); } return 0; }
相关文章推荐
- POJ 3926 Parade 单调队列优化dp
- UVaLive 4327 | POJ 3926 - Parade (单调队列优化DP)
- POJ Cut the Sequence 单调队列优化DP入门题
- 线段树和单调队列优化DP---POJ2373解题报告
- POJ 1821 Fence 单调队列优化DP
- poj 3017 Cut the Sequence dp+单调队列优化
- hdu Parade(单调队列优化 dp)
- 每日一dp(1)——Largest Rectangle in a Histogram(poj 2559)使用单调队列优化
- poj 2018 Best Cow Fences dp+单调队列优化
- POJ 2823 Sliding Window 单调队列优化DP
- poj 3017 单调队列优化DP
- poj 3017 dp+单调队列优化
- poj 2823 单调队列优化DP
- POJ 3017 单调队列优化DP
- POJ 1821 Fence(DP+单调队列优化)
- POJ 1821 单调队列优化DP
- uva-1427 Parade (单调队列优化dp)
- 线段树和单调队列优化DP---POJ2373解题报告
- [POJ 3926][Vjudge 19611] Parade [动态规划+单调队列]
- POJ2373...单调队列优化DP...