zoukankan      html  css  js  c++  java
  • 单调队列优化动态规划

    先来看这道题:

    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
    ", ans);
    40     return 0;
    41 }
  • 相关阅读:
    android 中webview调用js
    android apk打包之后js调用失效的解决办法
    android软键盘的管理和属性的设置
    android Bitmap(将视图转为bitmap对象)
    android的四种加载模式
    android 从其他app接收分享的内容
    android ADT 设置编辑字体
    android的JNI标准 android的NDK
    iOS开发随笔--iOS捕获异常、常用的异常处理方法
    IOS学习笔记--Objective-C之协议、代码块、分类
  • 原文地址:https://www.cnblogs.com/OIerPrime/p/9745970.html
Copyright © 2011-2022 走看看