码迷,mamicode.com
首页 > 其他好文 > 详细

单调队列优化动态规划

时间:2018-10-05 21:56:06      阅读:276      评论:0      收藏:0      [点我收藏+]

标签:位置   div   ges   window   notice   disco   ssis   typedef   cut   

先来看这道题:

USACO 2011 Open Gold Mowing the Lawn 修剪草坪

After winning the annual town competition for best lawn a year ago,
Farmer John has grown lazy; he has not mowed the lawn since then
and thus his lawn has become unruly. However, the competition is
once again coming soon, and FJ would like to get his lawn into
tiptop shape so that he can claim the title.

Unfortunately, FJ has realized that his lawn is so unkempt that he
will need to get some of his N (1 <= N <= 100,000) cows, who are
lined up in a row and conveniently numbered 1..N, to help him. Some
cows are more efficient than others at mowing the lawn; cow i has
efficiency E_i (0 <= E_i <= 1,000,000,000).

FJ has noticed that cows near each other in line often know each
other well; he has also discovered that if he chooses more than K
(1 <= K <= N) consecutive (adjacent) cows to help him, they will
ignore the lawn and start a party instead. Thus, FJ needs you to
assist him: determine the largest total cow efficiency FJ can obtain
without choosing more than K consecutive cows.

显然这是一道动态规划题目,我们先简化题目。题意是这样的:

FJ 有 N(1≤N≤100000) 只排成一排的奶牛,编号为 1...N。每只奶牛的效率是不同的, 奶牛 i 的效率为 Ei(0≤Ei≤1000000000)。靠近的奶牛们很熟悉,因此,如果 FJ 安排超过 K(1≤K≤N) 只连续的奶牛,那么,这些奶牛就会罢工去开派对。现在 FJ 需要你帮助计算可以得到的最大效率。

如果我们用 dp[i] 来表示前i头奶牛的最大效率,那么我们可以写出这样的转移方程:

dp[i]=max?{dp[j?1]+sum[i]?sum[j]} (i?K≤j≤i)

这样的转移方程的时间复杂度是O(NK),观察这道题的数据量,相当于O(N^2),显然是不行的。

仔细观察,实际上对于 dp[i] 来说,我们需要找到一个决策 j(i?K≤j≤i) 使得 dp[j?1]?sum[j] 最大化。再看,不难发现,i和j都是单调递增的,这让我们联想到以前做过的Sliding Windows,窗户的两边也是单调的对吧。所以这道题我们其实也可以用单调队列来优化。我们用这个单调队列来维护这个下标j的位置。

 1 #include <stdio.h>
 2 
 3 typedef long long LL;
 4 const int maxn = 100010;
 5 LL dp[maxn], sum[maxn];
 6 int que[maxn], E[maxn];
 7 int head, tail;
 8 LL max(LL a, LL b) {
 9     return a > b? a : b;
10 }
11 void add(int j) {
12     while (head < tail && dp[j - 1] - sum[j] >= (que[tail - 1] > 0 ? dp[que[tail - 1] - 1] : 0) - sum[que[tail - 1]]) {
13         --tail;
14     }
15     que[tail++] = j;
16 }
17 void del(int j) {
18     if (head < tail && que[head] == j) {
19         ++head;
20     }
21 }
22 int main() {
23     int n, k;
24     scanf("%d %d", &n, &k);
25     sum[0] = 0;
26     for (int i = 1; i <= n; ++i) {
27         scanf("%d", &E[i]);
28         sum[i] = sum[i - 1] + E[i];
29     }
30     dp[0] = 0;
31     que[tail++] = 0;
32     for (int i = 1; i <= n; ++i) {
33         add(i);
34         del(i - k - 1);
35         int j = que[head];
36         dp[i] = (j > 0 ? dp[j - 1] : 0) + sum[i] - sum[j];
37     }
38     LL ans = max(dp[n], dp[n - 1]);
39     printf("%lld\n", ans);
40     return 0;
41 }

 

单调队列优化动态规划

标签:位置   div   ges   window   notice   disco   ssis   typedef   cut   

原文地址:https://www.cnblogs.com/OIerPrime/p/9745970.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!