F - Bamboo Partition
传送门:https://codeforces.com/contest/831/problem/F
题意:
n颗竹子,从0开始每天都长高1米。他希望每颗竹子最后的高度为ai。
他每隔d天会来检查一次,并把所有超过预期高度的竹子砍成期望的高度。砍过的竹子不会再生长
限制条件:砍下的总长不可超过k
求最大的d。
令砍下的总长为sum,则有:
\[sum=\sum_{i=1}^{n}\lceil \frac{a_i}{d} \rceil d - a_i\\=\sum_{i=1}^{n}\lfloor \frac{a_i-1}{d}+1 \rfloor d - a_i
\]
\[要满足sum<=k
\]
\[k +\sum_{i=1}^{n} a_i \le nd+\sum_{i=1}^{n}\lfloor\frac{a_i-1}{d}\rfloor
\]
\[所以d的取值一定小于等于 k+\sum_{i=1}^{n}a_i
\]
右边可以分块求得。所以只需枚举d。
\[\sum_{i=1}^{n}\lceil \frac{a_i}{d} \rceil d - a_i \le k\\\sum_{i=1}^{n}\lceil \frac{a_i}{d} \rceil d\le k+\sum_{i=1}^{n}a_i\\d\sum_{i=1}^{n}\lceil \frac{a_i}{d} \rceil \le k+\sum_{i=1}^{n}a_i
\]
\[d或sqrt(k+\sum_{i=1}^{n}a_i)/d的取值在sqrt(k+\sum_{i=1}^{n}a_i)之内(我也还没想明白为什么,有没有大佬浇浇我)
\]
然后就暴力枚举所有可能的d。
#include<bits/stdc++.h>
#define int long long
int n, k; long long Sn;
int a[110];
std::set<int>se;
int f(int d) {
int ans = d * n - Sn;
for (int i = 1,r; i <= n; i = r + 1) {
int val = (a[i]) / d * d;
r = std::lower_bound(a + 1, a + 1 + n, (a[i] / d+ 1) * d ) - a - 1;
//std::cout << r << std::endl;
ans += val * (r - i + 1);
//std::cout << ans << std::endl;
}
return ans;
}
bool check(int d) {
if (d == 0)return 0;
if (f(d) <= k)return 1;
return 0;
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin >> n >> k;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
Sn += a[i];
a[i]--;
}
std::sort(a + 1, a + 1 + n);
int ans = 1;
for (int d = 1; d <= std::sqrt(k + Sn); d++) {
if (check(d))ans = std::max(d, ans);
if (check((k + Sn) / d))ans = std::max((k+Sn) / d, ans);
}
std::cout << ans<< std::endl;
}
浙公网安备 33010602011771号