阶段 1:输入处理与数据预处理
- 目标:读取输入数据,并将物体按位置排序,保证从左到右处理区间。
- 操作:读取多组测试用例(T 组),每组先读物体数量 n、选取组数 m;按题目要求的输入顺序:先批量读取所有物体的高度 h,再批量读取所有物体的位置 x;将每个物体的 (x, h) 封装为结构体,按位置 x 升序排序(确保从左到右处理区间,避免漏判重叠)。
阶段 2:区间分组(核心逻辑)
- 目标:将重叠 / 连续的物体归为一个 “组”,统计每个组的物体数量。
- 核心规则:若物体 A 的覆盖区间
[x_A, x_A+h_A]的右端点 ≥ 物体 B 的位置 x_B,则 A 和 B 属于同一组; - 操作:初始化:第一个物体为第一组,组内数量t=1,组的最远覆盖位置cmp = a[0].x + a[0].h;遍历所有物体(从第 1 个到第 n-1 个):若当前组的最远覆盖位置cmp ≥ a[i+1].x:说明和下一个物体重叠,组数量t++,并更新组的最远覆盖位置为max(cmp, a[i+1].x + a[i+1].h);若不重叠:当前组结束,将组数量t存入大顶堆,重置新组(t=1,cmp更新为下一个物体的覆盖右端点);处理最后一组:遍历结束后,将最后一个组的数量t存入大顶堆(避免遗漏)。
阶段 3:选取最大 m 组求和
- 目标:从所有组中选最大的 m 个组的数量求和,结果不超过总物体数 n。
- 操作:利用大顶堆(priority_queue)的特性(堆顶始终是最大值),依次取出前 m 个最大值累加;若累加和 ≥ n,输出 n(因为总物体数只有 n);否则输出累加和。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct p{
ll x,h;
// 排序规则:按物体位置x升序,保证从左到右处理区间
bool operator<(const p&other)const{
return x<other.x;
}
};
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
ll T;
cin>>T;
while(T--){
ll n,m;
cin>>n>>m;
vector<p>a(n);
// ========== 阶段1:输入处理 ==========
// 1.1 按题目要求读入所有物体的高度h
for(ll i=0;i<n;i++){
cin>>a[i].h;
}
// 1.2 按题目要求读入所有物体的位置x
for(ll i=0;i<n;i++){
cin>>a[i].x;
}
// 1.3 按位置x升序排序,保证从左到右处理区间
sort(a.begin(),a.end());
// ========== 阶段2:区间分组 ==========
priority_queue<ll>q; // 大顶堆:存储每个组的物体数量,方便取最大值
ll t=1; // 当前组的物体数量,初始为第一个物体
ll cmp=a[0].x+a[0].h; // 当前组的最远覆盖位置(右端点)
for(ll i=0;i<n;i++){
// 2.1 处理最后一个物体:将最后一组存入堆
if(i==n-1){
q.push(t);
break;
}
// 2.2 判定是否与下一个物体同组:当前组覆盖下一个物体的位置 → 同组
if(cmp>=a[i+1].x){
t++; // 组数量+1
cmp=max(cmp,a[i+1].x+a[i+1].h); // 更新组的最远覆盖位置
}else{
// 2.3 不同组:当前组结束,存入堆,重置新组
q.push(t);
t=1;
cmp=a[i+1].x+a[i+1].h;
}
}
// ========== 阶段3:选取最大m组求和 ==========
ll i=0,ans=0;
// 取前m个最大的组数量累加
while(!q.empty()&&i<m){
ans+=q.top();
q.pop();
i++;
}
// 结果不超过总物体数n
ans=min(ans,n);
cout<<ans<<'\n';
}
return 0;
}