题解:MX A. 小组作业

MX A. 小组作业

标签:二分。

还是太菜了,看不出来……

题面

班级中共有 个同学,每个同学至多愿意做小组作业 \(a_i\) 次。

每次小组作业需要找出 \(k\) 个不同的人共同完成,请问整个班级至多可以做完成多少次小组作业。

分析

二分能完成的小组作业次数,然后 check。

check

sum += min(mid, a[i]);
return sum >= mid * k;
正确性证明

能完成 mid 次小组作业,或者说将每个人都分入至少 mid 组,

则 sum 可以理解为所有有效的(可参与分配的)人的总数,看这些人可以在每一组中凑够 k 个人,就是能否分为 k 组,

为何是正确的?

如果他不能分为 mid 组,则有人不能分出 mid 个,由于我们限制每个人最多贡献 mid,所以不会有多贡献的情况,少了就是少了,没法补回来。

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1e5 + 10;

int a[N];
//int tree[N];
//
//int lowbit(int x) {
//	return x & (-x);
//}
//void add(int x, int d) {
//	for(int i = x;i < N;i += lowbit(i)) {
//		tree[i] += d;
//	}
//}
//int query(int x) {
//	int res = 0;
//	for(int i = x;i;i -= lowbit(i)) {
//		res += tree[i];
//	}
//	return res;
//}
//void sub(int x, int y, int d) {
//	add(x, -d);
//	add(y + 1, d);
//}
//
//priority_queue<int> q;

int n, k;
bool check(int mid) {
	int sum = 0;
	for(int i = 1;i <= n;i ++ ) {
		sum += min(mid, a[i]);
	}
	if(sum >= mid * k) return 1; // 能凑出来 sum / k > mid
	return 0; 
}

signed main() {
	ios :: sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	freopen("group.in", "r", stdin);
	freopen("group.out", "w", stdout); 
	int T;
	cin >> T;
	while(T -- ) {
		cin >> n >> k;
		int ans, l, r = 0;
		for(int i = 1;i <= n;i ++ ) {
			cin >> a[i];
			r += a[i];
		}
		l = 1;
		while(l <= r) {
			int mid = (l + r) >> 1;
			if(check(mid)) {
				ans = mid;
				l = mid + 1;
			}
			else r = mid - 1;
		}
		cout << ans << "\n";
	}
	return 0;
}

启示:要敢想敢猜,大胆猜测小心求证。

posted @ 2025-09-16 19:50  yanbinmu  阅读(6)  评论(0)    收藏  举报