题解 P7839 「Wdoi-3」夜雀 singing
被神仙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;
}