题解: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;
}
启示:要敢想敢猜,大胆猜测小心求证。

浙公网安备 33010602011771号