CF2200F Mooclear Reactor 2 题解
如果我们已经选定了一堆粒子的话,那么这组粒子最多可以同时存在的粒子数一定是有这些粒子中最小的\(y\)值所决定的。如果不考虑从商店加入粒子的话,我们可以从\([1,n+1]\)枚举集合中粒子的数量,求出在选出一定粒子数量\(k\)的情况下可以得到的最大总和。我们从大到小进行枚举,每次向优先队列中加入\(y \ge k-1\)的粒子,然后如果队列里面的元素数量超过了最多可以容纳的数量\(k\),那么就弹出最小的。因为\(k\)是不断变小的,这样可以保证总是从上一轮中留下来的最大值和当前要加入的元素中选择最大的\(k\)个。
接下来考虑从商店加入粒子应该怎么做,显然有两种情况:第一种是不选这个粒子,那么就是之前所有情况下和的最大值。第二种是选这个粒子,那么对于粒子数量为\(k\)的集合而言,我们需要去掉一个最小的,然后放入当前这个商店的粒子,我们只需要在枚举粒子数量\(k\)的时候记录一下数量为\(k\)的集合中最小的元素是什么,然后从维护一个去掉最小元素的总和的前缀最大值就可以。
#include <bits/stdc++.h>
using namespace std;
/*
*/
#define int long long
#define ll long long
#define double long double
#define i128 __int128_t
#define pii pair<int,int>
struct node{
ll x,y;
bool operator<(const node&other)const {
if(y==other.y) return x<other.x;
return y>other.y;
}
};
void sol() {
int n,m;
cin>>n>>m;
vector<node> becy(n),shop(m);
vector<int> ff(n+2,0),minNumber(n+2,0),f1(n+2,0),f2(n+2,0);
for(int i=0;i<n;i++) cin>>becy[i].x>>becy[i].y;
for(int i=0;i<m;i++) cin>>shop[i].x>>shop[i].y;
ll sum=0;
sort(becy.begin(),becy.end());
priority_queue<int,vector<int>,greater<int>> q;
for(int number=n+1,i=0;number>=1;number--){
while(i<n&&becy[i].y>=number-1){
q.push(becy[i].x);
sum+=becy[i].x;
i++;
}
while(q.size()>number){
sum-=q.top();
q.pop();
}
ff[number]=sum;
if(q.size()==number) minNumber[number]=q.top();
else minNumber[number]=0;
}
for(int number=1;number<=n+1;number++){
f1[number]=max(ff[number],f1[number-1]);
f2[number]=max(ff[number]-minNumber[number],f2[number-1]);
}
for(int i=0;i<m;i++){
cout<<max(f1[n+1],f2[shop[i].y+1]+shop[i].x)<<' ';
}
cout<<'\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
sol();
}
return 0;
}
总结:对于给定有限次修改机会后求答案的问题,可以先从不修改求答案出发。

浙公网安备 33010602011771号