题目描述:
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;
}