[P5858]「SWTR-03」Golden Sword(單調佇列優化dp)
阿新 • • 發佈:2020-08-07
【原題】
題目背景
小 E 不幸在一場戰鬥中失去了他的金寶劍。
題目描述
製造一把金寶劍需要 \(n\)種原料,編號為 \(1\) 到 \(n\),編號為 \(i\) 的原料的堅固值為 \(a_i\)。
鍊金是很講究放入原料的順序的,因此小 E必須按照 \(1\) 到 \(n\) 的順序依次將這些原料放入鍊金鍋。
但是,鍊金鍋的容量非常有限,它最多隻能容納 \(w\)個原料。
所幸的是,每放入一個原料之前,小E可以從中取出一些原料,數量不能超過 \(s\) 個。
- 我們定義第 iii 種原料的耐久度為:放入第 \(i\) 種原料時鍋內的原料總數 \(×a_i\),則寶劍的耐久度為所有原料的耐久度之和。
小 E\mathrm{E}E 當然想讓他的寶劍的耐久度儘可能得大,這樣他就可以帶著它進行更多的戰鬥,請求出耐久度的最大值。
注:這裡的“放入第 iii 種原料時鍋內的原料總數包括正在放入鍋中的原料,詳細資訊請見樣例。
輸入格式
第一行,三個整數 \(n, w, s\)。
第二行,\(n\)個整數 \(a_1,a_2,…,a_n\)。
輸出格式
一行一個整數,表示耐久度的最大值。
輸入輸出樣例
輸入 #1
5 3 3
1 3 2 4 5
輸出 #1
40
輸入 #2
5 3 3
1 -3 -2 4 5
輸出 #2
21
輸入 #3
7 4 2
-5 3 -1 -4 7 -6 5
輸出 #3
17
輸入 #4
5 3 1
-1 -3 -2 -4 -5
輸出 #4
-15
【思路】
確定上一層可轉移到當前狀態的範圍,取最大值即可,取最大值用單調佇列優化。
AC程式碼:
#include <algorithm> #include <cmath> #include <cstdio> #include <cstring> #include <list> #include <map> #include <iostream> #include <iomanip> #include <queue> #include <set> #include <stack> #include <string> #include <unordered_map> #include <vector> #define LL long long #define inf 0x3f3f3f3f #define INF 0x3f3f3f3f3f3f #define PI 3.1415926535898 #define F first #define S second #define endl '\n' #define lson rt << 1 #define rson rt << 1 | 1 #define f(x, y, z) for (LL x = (y), __ = (z); x < __; ++x) #define _rep(i, a, b) for (LL i = (a); i <= (b); ++i) using namespace std; const int maxn = 5507; const int maxm = 2e4 + 7; const int mod = 998244353; LL n, w, s; LL a[maxn]; LL dp[maxn][maxn]; int main() { ios::sync_with_stdio(false); cin.tie(0); LL ans = -INF; cin >> n >> w >> s; _rep(i, 1, n) cin >> a[i]; _rep(i, 1, n) { _rep(j, 1, n) dp[i][j] = -INF; } dp[1][1] = a[1]; deque<LL> q; _rep(i, 2, n) { q.clear(); for (LL j = w; j >= min(i - 1, w); j--) { while (!q.empty() && dp[i - 1][q.back()] <= dp[i - 1][j]) q.pop_back(); q.push_back(j); } for (LL j = min(i, w); j >= 1; j--) { while (!q.empty() && q.front() > j + s - 1) q.pop_front(); if (j > 1) { while (!q.empty() && dp[i - 1][q.back()] <= dp[i - 1][j - 1]) q.pop_back(); q.push_back(j - 1); } dp[i][j] = a[i] * j + dp[i - 1][q.front()]; } } _rep(i, 1, n) { ans = max(ans, dp[n][i]); } cout << ans << endl; }
TLE程式碼:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <list>
#include <map>
#include <iostream>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define LL long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f
#define PI 3.1415926535898
#define F first
#define S second
#define endl '\n'
#define lson rt << 1
#define rson rt << 1 | 1
#define f(x, y, z) for (LL x = (y), __ = (z); x < __; ++x)
#define _rep(i, a, b) for (LL i = (a); i <= (b); ++i)
using namespace std;
const int maxn = 5507;
const int maxm = 2e4 + 7;
const int mod = 998244353;
LL n, w, s;
LL a[maxn];
LL dp[maxn][maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
LL ans = -INF;
cin >> n >> w >> s;
_rep(i, 1, n) cin >> a[i];
_rep(i, 1, n)
{
_rep(j, 1, n) dp[i][j] = -INF;
}
dp[1][1] = a[1];
_rep(i, 2, n)
{
_rep(j, 1, min(i, w))
{
LL tmp = -INF;
_rep(k, max(1LL, j - 1), min(i - 1, min(w, j + s - 1)))
{
tmp = max(tmp, dp[i - 1][k]);
}
dp[i][j] = tmp + a[i] * j;
}
}
_rep(i, 1, n)
{
ans = max(ans, dp[n][i]);
}
cout << ans << endl;
}