题解:CF2252C Risky Tower
思路
分析题意的两种操作,找到满足其一的最小移除方块数。
- 任意一行的稳定性
v_i 降低到0 。 - 任意一行的块数为
0 。
根据条件
思考条件
考虑贪心,维护一个最小堆,存储每一行完成操作
时间复杂度
流程
-
从下往上遍历二维数组。
-
建立最小堆的优先队列
q 。 -
将
a_{i,j} 放入q 。- 若
sum - q.top() \geq v_i 或者cnt > ans ,则不断弹出堆顶(最小值)。
- 若
-
所有进出队列操作记得维护
sum 和cnt 。 -
细节注意
\texttt{long long} 。
代码
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n'
#define ll long long
void solve() {
int n, m;
cin >> n >> m;
vector<int>v(n + 1);
for (int i = 1; i <= n; i++) cin >> v[i];
vector<vector<int>> a(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
priority_queue<int, vector<int>, greater<int> >q;
ll sum = 0, cnt = 0, ans = m;
for (int i = n; i >= 1; i--) {
for (int j = 1; j <= m; j++) {
q.push(a[i][j]);
cnt ++; sum += a[i][j];
while (cnt > ans || sum - q.top() >= v[i]) {
sum -= q.top(); q.pop(); cnt--;
}
if (sum >= v[i])ans = min(ans, cnt);
}
}
cout << ans << endl;
}
signed main() {
io; int t = 1; cin >> t;
while (t--) {
solve();
}
return 0;
}