D:
题目链接
分析:
猜想:最优解吃的盘数一定等于最大盘数
n
/
(
k
+
1
)
n/(k+1)
n/(k+1)。因为一共有
n
n
n盘,每
(
k
+
1
)
(k+1)
(k+1)分钟会拿一盘并吃掉它(注意,不一定拿走一盘寿司就得立刻开吃)
证明采用反证法:令
c
n
t
cnt
cnt为最优解吃的盘数,假设
c
n
t
<
n
/
(
k
+
1
)
cnt<n/(k+1)
cnt<n/(k+1),那么最优解一定剩余超过
(
k
+
1
)
(k+1)
(k+1)盘(即
n
/
(
k
+
1
)
∗
(
k
+
1
)
−
c
n
t
∗
(
k
+
1
)
≥
k
+
1
n/(k+1) * (k+1) - cnt*(k+1) \geq k+1
n/(k+1)∗(k+1)−cnt∗(k+1)≥k+1),既然剩余超过
(
k
+
1
)
(k+1)
(k+1)盘说明还可以多吃一盘(只需要拿其中的第一个,后续还有
k
k
k个空位来吃掉它),因为还能多吃一盘因此与之前假设是最优解矛盾!
c
n
t
cnt
cnt不可能大于
n
/
(
k
+
1
)
n/(k+1)
n/(k+1)所以
c
n
t
cnt
cnt只能等于,证毕。
从后往前考虑,令
t
o
t
=
n
/
(
k
+
1
)
tot=n/(k+1)
tot=n/(k+1),
a
t
o
t
=
n
−
(
k
+
1
)
,
a
t
o
t
−
1
=
n
−
2
(
k
+
1
)
,
a
t
o
t
−
3
=
n
−
3
(
k
+
1
)
…
a
1
=
n
−
t
o
t
(
k
+
1
)
a_{tot}=n-(k+1),a_{tot-1}=n-2(k+1),a_{tot-3}=n-3(k+1) \ldots a_1=n-tot(k+1)
atot=n−(k+1),atot−1=n−2(k+1),atot−3=n−3(k+1)…a1=n−tot(k+1),
a
i
a_i
ai表示吃的第
i
i
i盘寿司位置最大在哪,这样就可以将吃的第
i
i
i盘寿司替换成前面的某一盘寿司,但是不能替换成后面的某一盘,那么吃的第一盘寿司可以替换成
[
1
,
a
1
]
[1,a_1]
[1,a1]这些下标美味值最大的一盘,并删掉美味值最大的那盘,第二盘就可以替换成
[
1
,
a
2
]
[1,a_2]
[1,a2]这些下标美味值最大的一盘,同样删掉美味值最大的那盘,以此类推。
一道贪心题,可以用multiset做,也可以用priority_queue做。
multiset做法:
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
int _ = 1;
cin >> _;
while (_ -- ) {
int n, k;
cin >> n >> k;
multiset<int> m;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
int res = 0;
for (int i = 1; i <= n; i++) {
m.insert(a[i]);
if ((n - i + 1) % (k + 1) == 0) {
res += *m.rbegin();
m.erase(-- m.end());
}
}
cout << res << "\n";
}
return 0;
}
priority_queue做法:
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
int _ = 1;
cin >> _;
while (_ -- ) {
int n, k;
cin >> n >> k;
priority_queue<int> m;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
int res = 0;
for (int i = 1; i <= n; i++) {
m.push(a[i]);
if ((n - i + 1) % (k + 1) == 0) {
res += m.top();
m.pop();
}
}
cout << res << "\n";
}
return 0;
}

被折叠的 条评论
为什么被折叠?



