uvalive4327(单调队列优化)

这题我有闪过是用单调队列优化的想法,也想过有左右两边各烧一遍。 但是不敢确定,搜了题解,发现真的是用单调队列,然后写了好久,调了好久下标应该怎么变化才过的。

dp[i][j] 表示走到第i行,第j个竖线的最大价值。

dp[i][j] = max(dp[i-1][k]+pre[i][j-1]-pre[i][k-1]);  从左往右

dp[i][j] = max(dp[i][j],dp[i-1][k]+suf[i][j]-suf[i][k]); 从右往左

 1 #pragma warning(disable:4996)
 2 #pragma comment(linker, "/STACK:1024000000,1024000000")
 3 #include <stdio.h>
 4 #include <string.h>
 5 #include <time.h>
 6 #include <math.h>
 7 #include <map>
 8 #include <set>
 9 #include <queue>
10 #include <stack>
11 #include <vector>
12 #include <bitset>
13 #include <algorithm>
14 #include <iostream>
15 #include <string>
16 #include <functional>
17 const int INF = 1 << 30;
18 typedef __int64 LL;
19 /*
20 dp[i][j]表示走到第i个横线,第j个竖线的最大值
21 dp[i][j] = max(dp[i-1][k] + sum[j-1] - sum[k-1])
22 单调队列优化维护队首最大值,
23 */
24
25 int q[11111], head, tail;
26 int dp[111][11111];
27 int a[111][11111];
28 int b[111][11111];
29 int pre[111][11111], suf[111][11111];
30 int sum1[111][11111];
31 int sum2[111][11111];
32 int main()
33 {
34     int n, m, k;
35
36     while (scanf("%d%d%d", &n, &m, &k),n+m+k)
37     {
38         memset(dp, 0, sizeof(dp));
39         memset(pre, 0, sizeof(pre));
40         memset(suf, 0, sizeof(suf));
41         memset(sum1, 0, sizeof(sum1));
42         memset(sum2, 0, sizeof(sum2));
43         n++;
44         for (int i = 1;i <= n;++i)
45         {
46             for (int j = 1;j <= m;++j)
47             {
48                 scanf("%d", &a[i][j]);
49                 pre[i][j] = pre[i][j - 1] + a[i][j];
50                 suf[i][j] = a[i][j];
51             }
52             for (int j = m;j >= 1;--j)
53                 suf[i][j] += suf[i][j + 1];
54
55         }
56         for (int i = 1;i <= n;++i)
57         {
58             for (int j = 1;j <= m;++j)
59             {
60                 scanf("%d", &b[i][j]);
61                 sum1[i][j] = b[i][j];
62                 sum2[i][j] = sum2[i][j - 1] + b[i][j];
63             }
64             for (int j = m;j >= 1;--j)
65                 sum1[i][j] += sum1[i][j + 1];
66         }
67         for (int i = n;i >= 1;--i)
68         {
69             head = tail = 0;
70             for (int j = 1;j <= m + 1;++j)
71             {
72                 while (head < tail && dp[i + 1][j] - pre[i][j - 1] >= dp[i + 1][q[tail - 1]] - pre[i][q[tail - 1] - 1])
73                     tail--;
74                 q[tail++] = j;
75                 while (head<tail && sum2[i][j-1] - sum2[i][q[head]-1]>k)
76                     head++;
77                 dp[i][j] = dp[i + 1][q[head]] + pre[i][j - 1] - pre[i][q[head]-1];
78             }
79             head = tail = 0;
80
81             for (int j = m+1;j >= 1;--j)
82             {
83                 while (head < tail&&dp[i + 1][j] - suf[i][j ] >= dp[i + 1][q[tail - 1]] - suf[i][q[tail - 1] ])
84                     tail--;
85                 q[tail++] = j;
86                 while (head<tail&&sum1[i][j] - sum1[i][q[head]]>k)
87                     head++;
88                 dp[i][j] =std::max(dp[i][j], dp[i + 1][q[head]] + suf[i][j] - suf[i][q[head]]);
89             }
90         }
91         int ans = 0;
92         for (int j = 1;j <= m + 1;++j)
93             ans = std::max(ans, dp[1][j]);
94         printf("%d\n", ans);
95     }
96     return 0;
97 }

时间: 2024-10-17 08:58:59

uvalive4327(单调队列优化)的相关文章

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完

codevs3327选择数字(单调队列优化)

3327 选择数字 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入描述 Input Description 第一行两个整数n,k 以下n行,每行一个整数表示a[i]. 输出描述 Output Description 输出一个值表示答案. 样例输入 Sample Input 5 2

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

hdu3401 Trade(单调队列优化dp)

Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4734    Accepted Submission(s): 1587 Problem Description Recently, lxhgww is addicted to stock, he finds some regular patterns after a few d

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 单调队列维护的是前

woj 1575 - Signal generators 单调队列优化dp + 瞎搞

戳这里:1575 题意:直线上排列着N个信号发射器,每个信号发射器被激活后将会使得影响范围内的所有发射器都被激活.询问激活任意一个发射器后被激活的发射器数最大是多少. 官方题解:可能会存在环的情况,考虑按坐标排序后i < j < k,j激活了k,然后k再激活i.但是这样可以转化为直接激活k的方案.所以无影响. 于是可以用dp求解.dp[i] = max( dp[j] + 1 ), position[j] + R[i] >= position[i],用单调队列优化时间复杂度为O(n). 向

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

题目链接:http://poj.org/problem?id=3017 题意:给你一个长度为n的数列,要求把这个数列划分为任意块,每块的元素和小于m,使得所有块的最大值的和最小 分析:这题很快就能想到一个DP方程 f[ i ]=min{ f[ j ] +max{ a[ k ] }}( b[ i ]<j<i,j<k<=i)     b[ i ]到 i的和大于m 这个方程的复杂度是O(n^2),明显要超时的(怎么discuss都说数据弱呢= =) 然后是优化了,首先当然是要优化一个最大

使用单调队列优化的 O(nm) 多重背包算法

我搜索了一下,找到了一篇很好的博客,讲的挺详细:链接. 解析 多重背包的最原始的状态转移方程: 令 c[i] = min(num[i], j / v[i]) f[i][j] = max(f[i-1][j-k*v[i]] + k*w[i])     (1 <= k <= c[i])  这里的 k 是指取第 i 种物品 k 件. 如果令 a = j / v[i] , b = j % v[i] 那么 j = a * v[i] + b. 这里用 k 表示的意义改变, k 表示取第 i 种物品的件数比

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