CF2063D Game With Triangles 反悔贪心
一开始想法是对的,但是写的丑了导致大数据一直没过去
由于我们只关心所选的区间长度和剩余的点的数量,并不关心具体选了哪些点,所以按照反悔贪心一贯的,用优先队列来储存选了哪些区间和哪些区间未选,剩余点的数量用n,m表示即可。用l,r双指针的方式从首尾选区间固然可以,但是这样就维护了额外的多余的量,容易出错
```cpp
#include<bits/stdc++.h>
using namespace std;
long long t;
const long long N = 2e5 + 10;
long long n,m,k;
long long a[N],b[N],ans[N];
void solve() {
for(long long i = 0;i <= k;i++) ans[i] = 0;
cin >> n >> m;
for(long long i = 1;i <= n;i++) cin >> a[i];
for(long long i = 1;i <= m;i++) cin >> b[i];
sort(a + 1,a + 1 + n);
sort(b + 1,b + 1 + m);
if(min(n,m) * 2 <= max(n,m)) k = min(n,m);
else k = (n + m) / 3;
cout << k << '\n';
priority_queue<long long> qa,qb;
priority_queue<long long,vector<long long>,greater<long long> > pa,pb;
//由于我仅仅只关注上下两条线各自点的数量和最大区间长度,并不关心该区间两端端点具体是什么,所以我们采用优先队列储存区间长度,n,m记录各自剩余点的个数即可,反悔的过程当中也仅仅只要用到各自剩余点的个数和已经加了的的区间长度
for(long long i = 1;i <= n / 2;i++) qa.push(a[n - i + 1] - a[i]);
for(long long i = 1;i <= m / 2;i++) qb.push(b[m - i + 1] - b[i]);
long long tmp = n + m,res = 0;
while(1) {
if(n >= 2 && m >= 2) {
n--,m--;
if(qa.top() > qb.top()) res += qa.top(),n--,pa.push(qa.top()),qa.pop();
else res += qb.top(),m--,pb.push(qb.top()),qb.pop();
}
else if(n >= 2) {
if(m == 0) {
if(pb.empty()) break;
res -= pb.top();
pb.pop();
m += 2;n++;
}
res += qa.top();
n -= 2;m--;
pa.push(qa.top());
qa.pop();
}
else if(m >= 2) {
if(n == 0) {
if(pa.empty()) break;
res -= pa.top();
pa.pop();
n += 2;m++;
}
res += qb.top();
m -= 2;n--;
pb.push(qb.top());
qb.pop();
}
else break;
ans[(tmp - n - m) / 3] = max(ans[(tmp - n - m) / 3],res);
}
for(long long i = 1;i <= k;i++) cout << ans[i] << ' ';
cout << '\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> t;
while(t--) solve();
return 0;
}