链接
传送门
题意
有\(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; }
|