1 条题解
-
0
自动搬运
来自洛谷,原作者为

itisover
招募ACM队友搬运于
2025-08-24 22:33:33,当前版本为作者最后更新于2021-08-28 21:31:00,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
被神仙slzs安利做了一下,可惜神仙slzs没能赛时切掉。
对于每一个鸟,我们可以处理出它左边最远能走到的点和右边能走到的最远的点,那么这个鸟能活动的范围就是一个区间。对于这个区间里面,如果有一个点的高度大于给出的时刻总数 ,那么这只鸟就是安全的,我们不用管了。对于不安全的鸟,我们要给它们放一些传送点,让它能够传到安全的地方。
首先,有一个传送点要放在一个高度大于给出的时刻总数 的位置,单独加上。可以发现,剩下的问题可以转化为:对于所有不安全的鸟的区间,放置最少的点使得所有区间都被覆盖,这是经典的最少点覆盖区间问题,可以用贪心解决。
我们把所有区间按左端点从小到大排序,然后贪心地选当前区间最远的点(右端点),如果这个区间的左端点大于上个区间的右端点,则说明需要再添加一个点,总点数加一即可,注意要处理一下有区间完全包含另一个区间的情况,这种情况只能取被包含的区间来算,我用了取 也可以解决这个问题。
回到处理每只鸟能走的区间的问题,如果单独考虑左右端点中的一个可以发现它具有单调不降,可以像马拉车类似的思想,如果之前的鸟能走到的最远的点小于等于当前鸟的位置,则暴力跑一遍跑出当前鸟的最远点并记录下来,如果之前的鸟能走到的最远点大于当前鸟的位置,则当前的鸟也一定可以走到那个最远点(因为走到最远点用掉的时间会比前一个点用时更少),所以直接从最远点开始跑暴力就行了。复杂度 。
至此我们解决了这题,别忘了最后的答案加上最开始单独考虑的 。
#include<bits/stdc++.h> using namespace std; template <class T> inline T read(){ T ans=0,f=0;char ch=getchar(); while(!isdigit(ch)) f|=ch=='-',ch=getchar(); while(isdigit(ch)) ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return f?-ans:ans; } const int N=5e6+5; int n,m,t,ans; int a[N],p[N],sum[N],vis[N]; struct zfz{ int l,r; }line[N]; bool cmp(zfz x,zfz y){return x.l<y.l;} int main(){ n=read<int>(),m=read<int>(),t=read<int>(); for(int i=1;i<=n;++i) a[i]=read<int>(); for(int i=1;i<=m;++i) p[i]=read<int>(); sort(p+1,p+1+m); int Max=0,T; for(int i=1;i<=m;++i){ if(p[i]>Max) T=0,Max=p[i]; else T=Max-p[i]; while(T+1<a[Max+1]) ++T,++Max; line[i].r=Max; } Max=n; for(int i=m;i;--i){ if(p[i]<Max) T=0,Max=p[i]; else T=p[i]-Max; while(T+1<a[Max-1]) ++T,--Max; line[i].l=Max; } sort(line+1,line+1+m,cmp); for(int i=1;i<=n;++i) sum[i]=sum[i-1]+(a[i]>t); for(int i=1;i<=m;++i) vis[i]=sum[line[i].r]-sum[line[i].l-1]>0?1:0; int last=0; for(int i=1;i<=m;++i){ if(vis[i]) continue; if(line[i].l>last) ++ans,last=line[i].r; else last=min(last,line[i].r); } if(!ans) puts("0"); else printf("%d",ans+1); return 0; }
- 1
信息
- ID
- 7108
- 时间
- 2000ms
- 内存
- 500MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者