题解:P11916 [PA 2025] 学区房 / Szkoła
思路:由于 \(n\) 数据范围过大,显然不能直接全部遍历。注意到所有区间两两不交,显然可以对所有的区间进行排序,然后从小到大对区间进行遍历,由于 \(m\) 并不算大,这种方案自然是可行的。
已知学校是在一个区间内的(保证编号为 \(s\) 的建筑不提供租赁服务)但不确定学校所在的区间两端是否有其他区间挨着它。我们直接将相邻的区间进行合并。需要合并的区间左端点不变,右端点向后延伸即可。
随着我们遍历完越来越多的区间,一定会等到一个区间包含学校所在的建筑。合并该区间,直到无法再合并,比较这个区间的左端点离学校近还是右端点离学校近,从而得出答案。
要注意的是,所求的这栋建筑不应该在此区间内,所以答案是左端点的左边一个,或右端点右边一个的位置。所求出的左端点为 \(1\),或右端点为 \(n\) 时,向左或向右一个都会超出题目所给的范围,这样就不合法。因此还需要特判左端点为 \(1\) 或右端点为 \(n\) 这两种情况。又因为题目保证有解,因此这种情况下只需要输出另外一个端点就可以了。到这里思路基本上清晰了。更多细节就请看代码注释。
AC代码如下
#include <bits/stdc++.h>
#define ll long long
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
ll n,s,p,q;
//学校所在区间的左端点为 p,学校所在区间的右端点为 q。
int m,flag;
struct node{
ll l,r;
}a[1145];
bool cmp(node a,node b){
return a.l<b.l;
//所有区间两两不交,因此左端点排序了右端点自动有序。
}
int main(){
ios;cin>>n>>m>>s;
for(int i=1;i<=m;i++){
cin>>a[i].l>>a[i].r;
}
sort(a+1,a+1+m,cmp);
for(int i=1;i<=m;i++){
if(a[i].r+1==a[i+1].l){
a[i+1].l=a[i].l;
//这样下一个区间左端点不变,右端点向右延伸。
continue;
}
if(a[i].l<=s&&a[i].r>=s){
//由于题目保证一定有解:
p=a[i].l-1,q=a[i].r+1,flag=1;
if(q>n)cout<<p;//右端点不合法则左端点为答案。
else if(p<1)cout<<q;//左端点不合法则右端点为答案。
else if(s-p<=q-s)cout<<p;//左端点比右端点离 s 近或距离相等取小的。
else if(s-p>q-s)cout<<q;//右端点比左端点离 s 近。显然用 else 也是可以的。
return 0;
}
}
}
感谢阅读!
本文来自博客园,作者:Circle_Table,转载请注明原文链接:https://www.cnblogs.com/Circle-Table/articles/19177403

浙公网安备 33010602011771号