zoukankan      html  css  js  c++  java
  • 洛谷P2627 修剪草坪 题解 单调队列优化DP

    题目链接:https://www.luogu.com.cn/problem/P2627

    解题思路:

    定义状态 (f[i]) 表示:"前 (i) 只奶牛,且当 (i < n) 时,第 (i+1) 只奶牛不选"的情况下的最大值。

    则,当 (i le k) 时,

    [f[i] = sum_{j=1}^{i} e[j] ]

    (i > t) 时,

    [f[i] = max_{j in [i-k-1, i-1]}(f[j] + sum_{x=j+2}^i e[x]) ]

    其中区间和我们可以额外开一个 sum 数组用于存储前缀和。

    实现代码如下(TLE代码):

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 100010;
    int n, k;
    long long e[maxn], sum[maxn], f[maxn], ans;
    int main() {
        cin >> n >> k;
        for (int i = 1; i <= n; i ++) {
            cin >> e[i];
            sum[i] = sum[i-1] + e[i];
        }
        if (k > n) k = n;
        for (int i = 1; i <= k; i ++) f[i] = sum[i];
        for (int i = k+1; i <= n; i ++)
            for (int j = 1; j <= k; j ++)
                f[i] = max(f[i], f[i-j-1] + sum[i] - sum[i-j]);
        for (int i = 1; i <= n; i ++)
            ans = max(ans, f[i]);
        cout << ans << endl;
        return 0;
    }
    

    但是这样的时间复杂度是 (O(n cdot k)) 的,会超时。

    于是考虑将上述的状态转移方程进行一下转化:

    [f[i] = max_{j in [i-k-1, i-1]}(f[j] - sum[j+1]) + sum[i] ]

    所以考虑将 (f[j] - sum[j+1]) 放到一个单调队列当中。

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 100010;
    int n, k;
    long long e[maxn], sum[maxn], f[maxn], ans;
    deque<int> que;
    long long cal(int i) {
        return f[i] - sum[i+1];
    }
    int main() {
        cin >> n >> k;
        for (int i = 1; i <= n; i ++) {
            cin >> e[i];
            sum[i] = sum[i-1] + e[i];
        }
        if (k > n) k = n;
        for (int i = 1; i <= k; i ++) f[i] = sum[i];
        int j = 0;
        for (int i = k+1; i <= n; i ++) {
            for (; j < i; j ++) {
                while (!que.empty() && cal(que.back()) <= cal(j)) que.pop_back();
                que.push_back(j);
            }
            while (que.front() < i-k-1) que.pop_front();
            f[i] = f[que.front()] - sum[que.front()+1] + sum[i];
        }
        for (int i = 1; i <= n; i ++)
            ans = max(ans, f[i]);
        cout << ans << endl;
        return 0;
    }
    

    然后我错了样例3,因为我一开始将 (j) 的初始坐标设为了 (1) ,后来改成了 (0) 就 AC 了。

    可以拿下面这组测试数据试一下:

    测试in

    6 1
    4
    7
    2
    0
    8
    9
    

    测试out

    16
    
  • 相关阅读:
    野心和实力的磨合
    tpm
    菜猫学习linux笔记(1)
    调试理解过程
    TSS学习记录
    RSA加密算法理解(整理自网络)
    *args和**kwargs在python中的作用
    在 Ubuntu 16.04 中安装谷歌 Chrome 浏览器
    ubuntu安装微信客户端
    ubuntu 桌面操作系统安装WPS办公软件的方法
  • 原文地址:https://www.cnblogs.com/quanjun/p/12284548.html
Copyright © 2011-2022 走看看