CF1185C2 Exam in BerSU (hard version)

题目描述:

Polygraph Poligrafovich 要去测试n位学生。学生们按照1到n的顺序依次测试。第i个考生随机抽取一题。学生可选做与不做,做则得到分数,不做则不及格。

所有学生总共考试时间是M,求对于第i个学生通过考试时,计算出前面最少的不及格的学生的人数。

输入:

n,M(1<=n,M<=100)

下面n个数表示第i个同学需要花费的时间ti

输出:

第i个学生通过考试时,计算出前面最少的不及格的学生的人数。

题解:

思路很简单,用一个大根堆heap储存前i个最大能通过的学生数中每个人的时间t,然后用sum在储存heap中所有元素的和。

在每次查询新的学生x时,如果time[x]+sum<=M则在heap中存入time[x],同时更新sum,输出结果即为i-heap.size()。

而如果time[x]+sum>M,分两种情况:

①time[x]<=heap.top(),则删除堆顶,同时将time[x]存入heap,同时更新sum,输出也为i-heap.size()。

②如果time[x]>heap.top(),由于当前学生x必须通过,故我们只需将heap的堆顶不断弹出,同时弹出时维护sum-=heap.top(),直至sum+time[x]<=M,输出i-heap.size()。(此处的heap和sum,后面依然要用到,所以我们可以用新的一组heap_t和sum_t储存后再操作)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m;
int a[N];
int sum = 0;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];

	priority_queue<int>heap;
	for (int i = 1; i <= n; i++) {
		if (sum + a[i] <= m) {
			heap.push(a[i]);
			sum += a[i];
		}
		else {
			int t = heap.top();
			if (a[i] < t) {//删除堆顶小于t的所有元素
				heap.pop();
				heap.push(a[i]);
				sum = sum - t + a[i];
			}
			else {
				priority_queue<int>heap_t = heap;
				int t = heap_t.top();
				int sum_t = sum;
				while (a[i] + sum_t > m) {//弹出堆顶并维护
					sum_t -= t;
					heap_t.pop();
					t = heap_t.top();
				}
				cout << i - heap_t.size() - 1 <<  ;
				continue;
			}
		}

		cout << i - heap.size() <<  ;

	}

	return 0;
}

​
经验分享 程序员 微信小程序 职场和发展