F - Bamboo Partition

CodeForces - 831F

传送门: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;
}

posted on 2022-07-15 11:43  wtn135687  阅读(39)  评论(0)    收藏  举报