NC16649 [NOIP2005]校门外的树
题目
题目描述
某校大门外长度为 的马路上有一排树,每两棵相邻的树之间的间隔都是 米。我们可以把马路看成一个数轴,马路的一端在数轴 的位置,另一端在 的位置;数轴上的每个整数点,即 都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入描述
第一行有两个整数:()和 (), 代表马路的长度, 代表区域的数目, 和 之间用一个空格隔开。接下来的 行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
输出描述
包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
示例1
输入
500 3 150 300 100 200 470 471
输出
298
题解
数据范围一(原题范围)
,
知识点:差分,枚举。
数组直接模拟整个区间,进行差分。
时间复杂度
空间复杂度
数据范围二(加强)
,
知识点:离散化,枚举。
端点代替区间,合并区间后求长与总长相减。
时间复杂度
空间复杂度
数据范围三(再加强)
,
知识点:离散化,差分,枚举。
已经无法用数组模拟区间,考虑模拟端点的差分值,累加目标区间长度。
时间复杂度
空间复杂度
代码
数据范围一(原题范围)
#include <bits/stdc++.h> using namespace std; int vis[10007];///模拟整个区间 int main(){ int L,M; cin>>L>>M; for(int i = 0;i<M;i++){ int l,r; cin>>l>>r; vis[l]++; vis[r+1]--;///差分 } int a = 0,ans = 0; for(int i = 0;i<=L;i++){ a += vis[i];///前缀和 if(!a) ans++;///加完之后是0,那说明此处无遮盖 } cout<<ans<<'\n'; return 0; }
数据范围二(加强)
#include <bits/stdc++.h> using namespace std; struct qj{ int l,r; }a[100007]; bool cmp(qj a,qj b){ return a.l == b.l?a.r<b.r:a.l<b.l; } int main(){ int L,M; cin>>L>>M; for(int i = 0;i<M;i++){ cin>>a[i].l>>a[i].r; } sort(a,a+M,cmp);///按左端点从小到大,再按右端点从小到大 int cnt = 0;///记录合并区间长度 int l = a[0].l,r = a[0].r;///记录初始合并区间 for(int i = 1;i<M;i++){ if(a[i].l<=r) r = max(r,a[i].r); ///当前区间左端点小于等于此合并区间的右端点(不是上个区间的右端点,这里错了tmd)(因为排序,当前区间左端点不可能小于上一个区间左端点) ///那么合并区间的右端点为自己和当前区间右端点的最大值 else{ cnt+=r-l+1; l = a[i].l; r = a[i].r; }///合并结束更新 } cnt+=r-l+1; cout<<L-cnt+1<<'\n';///L+1是总端点数 }
数据范围三(再加强)
#include <bits/stdc++.h> using namespace std; struct diff{ int pos; int num; }delta[100007];///记录特定端点代替整个区间,达到满足空间要求 bool cmp(diff a,diff b){ return a.pos==b.pos?a.num<b.num:a.pos<b.pos; } int main(){ std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int L,M; cin>>L>>M; for(int i = 0;i<M;i++){ int x,y; cin>>x>>y; delta[i].pos = x;///记录左端点 delta[i].num = 1; delta[i+M].pos = y+1;///记录右端点,因为差分所以y+1 delta[i+M].num = -1; } sort(delta,delta+2*M,cmp);///根据左端点从小到大排序,先负再正 int a = 0,cnt = 0; for(int i = 0;i<2*M;i++){ a += delta[i].num; if(a == 1 && delta[i].num == 1){///此时pos是0区域的右端点+1位置,上一个pos即左端点位置 cnt+=delta[i].pos - delta[i-1].pos;///相减即为区间长度 } } if(!a) cnt+=L-delta[2*M-1].pos+1; cout<<cnt<<'\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16246774.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧