1 条题解

  • 0
    @ 2025-8-24 22:33:33

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar itisover
    招募ACM队友

    搬运于2025-08-24 22:33:33,当前版本为作者最后更新于2021-08-28 21:31:00,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    被神仙slzs安利做了一下,可惜神仙slzs没能赛时切掉。

    对于每一个鸟,我们可以处理出它左边最远能走到的点和右边能走到的最远的点,那么这个鸟能活动的范围就是一个区间。对于这个区间里面,如果有一个点的高度大于给出的时刻总数 tt,那么这只鸟就是安全的,我们不用管了。对于不安全的鸟,我们要给它们放一些传送点,让它能够传到安全的地方。

    首先,有一个传送点要放在一个高度大于给出的时刻总数 tt 的位置,单独加上。可以发现,剩下的问题可以转化为:对于所有不安全的鸟的区间,放置最少的点使得所有区间都被覆盖,这是经典的最少点覆盖区间问题,可以用贪心解决。

    我们把所有区间按左端点从小到大排序,然后贪心地选当前区间最远的点(右端点),如果这个区间的左端点大于上个区间的右端点,则说明需要再添加一个点,总点数加一即可,注意要处理一下有区间完全包含另一个区间的情况,这种情况只能取被包含的区间来算,我用了取 minmin 也可以解决这个问题。

    回到处理每只鸟能走的区间的问题,如果单独考虑左右端点中的一个可以发现它具有单调不降,可以像马拉车类似的思想,如果之前的鸟能走到的最远的点小于等于当前鸟的位置,则暴力跑一遍跑出当前鸟的最远点并记录下来,如果之前的鸟能走到的最远点大于当前鸟的位置,则当前的鸟也一定可以走到那个最远点(因为走到最远点用掉的时间会比前一个点用时更少),所以直接从最远点开始跑暴力就行了。复杂度 Θ(n+m)\Theta(n+m)

    至此我们解决了这题,别忘了最后的答案加上最开始单独考虑的 11

    #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
    上传者