#875. 选元素(数据加强版)
思路:
如果题目是,每
k
k
k 个数中就必须选择一个,选择的总数固定,那么可以写出状态转移方程:
令
f
[
i
]
f[i]
f[i] 第
i
i
i 个元素时,选择到的最大值:
f
[
i
]
=
m
a
x
(
f
[
t
]
)
+
a
[
i
]
f[i] = max(f[t]) + a[i]
f[i]=max(f[t])+a[i] 其中
(
i
−
k
<
t
<
i
(i - k < t < i
(i−k<t<i),可以发现
f
[
t
]
f[t]
f[t] 可以用单调队列来维护
m
a
x
(
f
[
t
]
)
max(f[t])
max(f[t])(模板 单调队列优化dp)。
但是该题要求了选择的个数为
x
x
x,
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示 第
i
i
i 个元素,选择了
j
j
j 个时的最大值。
此时的状态转移方程:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
t
]
[
j
−
1
]
)
+
a
[
i
]
f[i][j] = max(f[t][j - 1]) + a[i]
f[i][j]=max(f[t][j−1])+a[i] 其中
(
i
−
k
<
t
<
i
(i - k < t < i
(i−k<t<i),
j
j
j 只能由
j
−
1
j - 1
j−1 更新而来,除此以外和上面情况完全相同,可以用单调队列维护
m
a
x
(
f
[
t
]
[
j
−
1
]
)
)
max(f[t][j - 1]))
max(f[t][j−1]))
j
j
j 的值用一层循环来更新即可。最终答案在最后
k
k
k 个数中找最大值即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
const int N = 3e3 + 10;
ll s[N], f[N][N], sum;
int n, k, x, q[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
cin >> n >> k >> x;
for(int i = 1; i <= n; i ++) {
cin >> s[i];
// sum += s[i];
}
memset(f, -0x3f, sizeof f);
f[0][0] = 0;
for(int j = 1; j <= x; j ++) {
int hh = 0, tt = -1;
for(int i = 0; i <= n; i ++) {
if(hh <= tt && i - q[hh] > k) hh ++;
if(hh <= tt) f[i][j] = f[q[hh]][j - 1] + s[i];
// else f[i][j] = max(f[i][j], f[i - 1][j]);
while(hh <= tt && f[q[tt]][j - 1] <= f[i][j - 1]) tt --;
q[++ tt] = i;
}
}
ll ans = -1;
for(int i = n - k + 1; i <= n; i ++) ans = max(ans, f[i][x]);
cout << ans << '\n';
}
// 1 1 1 1 1 1 1
C. Jump and Treasure
题目大意,
n
n
n 个元素,
q
q
q 询问,每次最多往右跳
p
p
p 步,最开始在
0
0
0 的位置,每次询问如果每次跳
x
x
x 的倍数步,可以获得元素和的最大值是多少。
令
f
[
i
]
f[i]
f[i] 为跳到 第
i
i
i 个元素时获得的最大值, 那么
f
[
i
]
=
m
a
x
(
f
[
t
]
)
+
w
[
i
]
f[i] = max(f[t]) + w[i]
f[i]=max(f[t])+w[i] 其中
(
i
−
p
<
t
<
i
)
(i - p < t < i)
(i−p<t<i),也可也用单调队列来维护
f
[
i
]
f[i]
f[i] 的值,本题加了一个跳
x
x
x 的倍数步子的限制,对于每次询问,可以预先离散化处理出能够到达哪些点上,再用单调队列维护即可。因为存在多个
x
x
x 有可能相同,所以为了减少冗余操作,可以将询问先存下来再来计算;记得开
l
o
n
g
l
o
n
g
long long
longlong
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
ll qu[N], ans[N];
vector<int> query[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int n, q, p; cin >> n >> q >> p;
vector<ll> a(n + p + 10, 0);
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= q; i ++) {
int x; cin >> x;
if(x > p) ans[i] = -1e18;
else query[x].push_back(i);
}
for(int i = 1; i <= n; i ++) {
if(query[i].empty()) continue;
vector<int> jump;
jump.push_back(0);
for(int j = i; j <= n; j += i) jump.push_back(j);
jump.push_back(n + 1);
vector<ll> f(jump.size() + 10, -1e18);
f[0] = 0, qu[0] = 0;
int hh = 0, tt = 0;
for(int j = 1; j < jump.size(); j ++) {
while(hh <= tt && jump[j] - jump[qu[hh]] > p) hh ++;
f[j] = max(f[j], f[qu[hh]] + a[jump[j]]);
while(hh <= tt && f[j] >= f[qu[tt]]) tt --;
qu[++ tt] = j;
}
for(auto id : query[i]) ans[id] = f[jump.size() - 1];
}
for(int i = 1; i <= q; i ++) {
if(ans[i] == -1e18) cout << "Noob" << '\n';
else cout << ans[i] << '\n';
}
}
// 1 1 1 1 1