Codeforces 748E - Santa Claus and Tangerines

链接

传送门

题意

\(n\)个橘子,分给\(k\)个人。每次可以选择一个橘子块进行均分,如果橘子的大小为奇数则其中一块比另一块大1。橘子块可以有剩余,问最后\(k\)个人中分得橘子的最小值的最大值是多少。

思路

练习赛做的题,一个很显然的贪心是每次都均分最大的橘子块,最后取最大的\(k\)块。一开始用map离散化了一下,然后类似双指针那样进行处理,超时了。后来用二分+DP卡常数过了。

赛后看了题解恍然大悟,根本不用离散化,1e7的数据量直接存下来然后双指针扫一遍就行了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int maxn = 10000010;

LL a[maxn];

int main() {
int n, k;
LL sum = 0;
scanf("%d%d", &n, &k);
for (int i = 0, x; i < n; ++i) {
scanf("%d", &x);
sum += x;
++a[x];
}
if (sum < k) {
puts("-1");
return 0;
}
sum = n;
int p1 = 0, p2 = maxn - 1;
while (sum < k) {
sum += a[p2];
a[p2 / 2] += a[p2];
a[(p2 + 1) / 2] += a[p2];
--p2;
}
while (sum - a[p1] >= k) {
sum -= a[p1];
++p1;
}
while (p1 < p2 / 2) {
sum += a[p2];
a[p2 / 2] += a[p2];
a[(p2 + 1) / 2] += a[p2];
--p2;
while (sum - a[p1] >= k) {
sum -= a[p1];
++p1;
}
}
printf("%d\n", p1);
return 0;
}