P5858 Golden Swold

寫在前面

簡單的單調隊列優化 DPc++

處理略微有點噁心,因而乎,用來取 \(\max\) 的極小值直接開到了 long long 的最小極限,了 define int long long /cygit

算法思路

必須按編號順序加材料,明顯的階段性,且數據範圍明顯地提示咱們能夠 DP算法

狀態也很好想,設 \(f_{i, j}\) 表示放完前 \(i\) 個物品後鍋內有 \(j\) 個物品時的最大答案。數組

那麼使用填表法轉移:優化

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

那麼發現 \(k\) 的取值範圍隨着 \(j\) 的變化恰好是個滑動窗口,其他的項都是輸入時或枚舉過程當中的定值,所以使用單調隊列優化取最大值的操做。spa

另外表示階段的 \(i\) 只會取到上一個階段的答案,所以開滾動數組壓掉第一維。code

Tips

建議把可能須要開 long long 的都打開,若是不以爲很傻或者比較懶的話也能夠直接 define int long long隊列

內層循環能夠倒序枚舉,這樣就只須要一開始的時候往單調隊列裏壓一個元素。不用亂七八糟的處理。ip

初始化極小值的時候要足夠小親測 \(-10^{12}\) 都不夠用,還不能在加上一些負值以後爆 long long 的最小範圍。get

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);
}
相關文章
相關標籤/搜索