zoukankan      html  css  js  c++  java
  • P5858 Golden Swold

    写在前面

    简单的单调队列优化 DP

    处理略微有点恶心,于是乎,用来取 (max) 的极小值直接开到了 long long 的最小极限,了 define int long long /cy

    算法思路

    必须按编号顺序加材料,明显的阶段性,且数据范围明显地提示我们可以 DP

    状态也很好想,设 (f_{i, j}) 表示放完前 (i) 个物品后锅内有 (j) 个物品时的最大答案。

    那么使用填表法转移:

    [f_{i, j} = max_{j - 1 le k le j + s - 1}{f_{i - 1,k}} + j imes a_i ]

    那么发现 (k) 的取值范围随着 (j) 的变化刚好是个滑动窗口,其余的项都是输入时或枚举过程中的定值,因此使用单调队列优化取最大值的操作。

    另外表示阶段的 (i) 只会取到上一个阶段的答案,因此开滚动数组压掉第一维。

    Tips

    建议把可能需要开 long long 的都打开,如果不觉得很傻或者比较懒的话也可以直接 define int long long

    内层循环可以倒序枚举,这样就只需要一开始的时候往单调队列里压一个元素。不用乱七八糟的处理。

    初始化极小值的时候要足够小亲测 (-10^{12}) 都不够用,还不能在加上一些负值之后爆 long long 的最小范围。

    Code

    /*
    
    By chen_green
    
    2020/11/5
    
    设 f[i][j]表示放完前 i 件物品后锅中已经放了 j 件物品的最大耐久度
    
    f[i][j] = max{f[i - 1][k]} + j * a[i] (j - 1 <= k <= j - 1 + s)
    
    滚动数组 + 单调队列优化
    
    */
    
    #include <bits/stdc++.h>
    #define int long long
    
    #define LL long long
    
    using namespace std;
    
    inline int read0() {
      int fh = 1, w = 0; char ch = getchar();
      for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
      for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
      return fh * w;
    }
    
    inline LL read() {
      LL fh = 1, w = 0; char ch = getchar();
      for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
      for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
      return fh * w;
    }
    
    const int Maxn = 5505;
    
    LL f[2][Maxn];
    
    LL a[Maxn];
    
    int n, w, s;
    
    deque<LL> dq;
    
    void initdq() {while(!dq.empty()) dq.pop_back();}
    void push(int x) {
      if((int)dq.size() >= (int)(s + 1)) dq.pop_front();
      while((!dq.empty()) && (dq.back() <= x)) dq.pop_back();
      dq.push_back(x);
    }
    LL Getmax() {
      return dq.front();
    }
    
    signed main() {
      n = read0(); w = read0(); s = read0();
      for(register int i = 1; i <= n; ++i) {
        a[i] = read();
      }
      for(register int i = 0; i <= w; ++i) f[0][i] = f[1][i] = -9223372036854775808 / 2;
      LL f0 = f[0][0];
      f[0][0] = 0;
      LL ans = -9223372036854775808;
      for(register int i = 1; i <= n; ++i) {
        if(i == 2) f[0][0] = f0;
        initdq();
        push(f[i - 1 & 1][w]);
        for(register int j = w; j >= 1; --j) {
          push(f[i - 1 & 1][j - 1]);
          f[i & 1][j] = Getmax() + j * a[i];
          //cout << f[i & 1][j] << " ";
        }
      }
      for(int i = 1; i <= w; ++i) {
        ans = max(ans, f[n & 1][i]);
      }
      printf("%lld", ans);
    }
    
    
  • 相关阅读:
    update(十)
    perl-basic-数据类型&引用
    R-barplot()
    leetcode-22-string
    Java-basic-7-面向对象
    Java-basic-6-方法
    Java-basic-4-数据类型
    Java-basic-3-运算符-修饰符-循环
    Java-basic-2-
    leetcode-21-knapsack
  • 原文地址:https://www.cnblogs.com/zimujun/p/13934381.html
Copyright © 2011-2022 走看看