1 条题解

  • 0
    @ 2025-8-24 21:44:03

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar gyfer
    **

    搬运于2025-08-24 21:44:03,当前版本为作者最后更新于2018-07-25 23:48:40,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    这是一道模拟题 思路:排序优化,模拟放置。


    HINT:先把被别人覆盖的丢掉。环?复制一遍当做序列来做。对每个壁纸求出能接在它后面的右端点最大的。(怎么求?)那之后咋办啊(掀桌) 我会!枚举作为起点的牛,然后不断地往后跑直到覆盖一整圈! ......n元环了解一下? 把牛看作点,每个点有且只有一条出边...基环内向树! 点权为壁纸长度,边权为增加的有效长度。 只要起点点权+各边权和>=C就好了。 类似于two pointer,随着起点往后跳,终点也随着往后跳。 可惜的是不管是正向还是反向复杂度都好像是错的。。 。

    首先把被完全覆盖的围栏去掉,剩下的按左端点升序排序。那么右端点肯定也是升序的了。。然后计算出每段围栏,它接下去一段围栏可达到的最远距离。枚举起点,贪心地一段一段接下去就可得到该起点的最优解。

    直接这样做显然会T。。


    正解

    换个方向...考虑某个答案啥时候会被计算到。 显然不管是啥答案,肯定有条跨过环的边。 枚举那条边...然后呢?总不能直接跑吧对每个点x预处理出f[x],pos[x]:以x为起点,一直跳到 即将跨环 (再走一步就跨环了)的时候,走了几条边,停在哪里。枚举跨环的初始边(x,y),之后y直接跑到pos[y],然后稍微判断一下。

    AC代码

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=200001;
    const int INF=0x3f3f3f;
    struct node{
        int l,r;
    }a[N];
    int nxt[N],pos[N],jump[N],tmpcos[N];
    int i,j,L,n,m,ans,k;
    bool cmp(node x,node y){
        return x.l==y.l?x.r>y.r:x.l<y.l;//排序了解一下
    }
    void get(int x){//得到当前牛所能到达的最远点
        if(jump[x]) return;
    
        if(a[x].r>=L){
            jump[x]=x;
            tmpcos[x]=0;
        }else{
            get(nxt[x]);
            jump[x]=jump[nxt[x]];
            tmpcos[x]=tmpcos[nxt[x]]+1;
        }
    }
    int main(){
        cin>>L>>n;
        for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r,a[i].r+=a[i].l;
        sort(a+1,a+n+1,cmp);
        int mx=-1,tmp=0;
        for(int i=1;i<=n;i++)//缩牛操作
          if(a[i].r>mx) {
              a[++tmp]=a[i];
              mx=a[i].r;
          }
        n=tmp;
        tmp=0;
        for(int i=1;i<=n;i++){//计算pos
            nxt[i]=nxt[i-1];
            for(;tmp<n&&a[tmp+1].l<=a[i].r;tmp++);
            if(tmp==i) nxt[i]=0;
            else{
                nxt[i]=tmp;
                pos[i]=a[tmp].r;
            }
            //cout<<nxt[i]<<endl;
        }
        int tmpsum,now;//tmpsum:计算牛的总数
        ans=INF;
        for(int i=1;i<=n;i++){
            if(!jump[i]) get(i);
            tmpsum=tmpcos[i]+1;
            now=jump[i];
            while(nxt[now]&&a[now].r<a[i].l+L&&tmpsum<ans){
                now=nxt[now];
                tmpsum++;
            }
            if(a[now].r>=a[i].l+L&&tmpsum<ans) ans=tmpsum;
        }
        cout<<ans<<endl;
        return 0;
    }
    
    • 1

    信息

    ID
    2045
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者