zoukankan      html  css  js  c++  java
  • [BZOJ 4082] Surveillance

    Link:

    BZOJ 4082 传送门

    Solution:

    对于链上这样的问题贪心就好了

    如果在一个环上,肯定需要将环转化成链,$O(n)$确定起点才能计算

    但枚举每个节点拆环再贪心的复杂度为$O(n^2)$,明显会超时

    于是我们要将已知起点,计算从起点走完一圈的距离的时间复杂度降到$log(n)$

    这时联想到倍增算法:

    将所有区间按照右端点排序后,将每个区间和其能达到的右端点最远的区间相连

    可以发现,这样就形成了一个$DAG$(每个点都只会向后连边)

    接下来只要对于每个点在$DAG$上倍增即可,计算当右端点回到该点起点时的距离

    Tip:$BZOJ$的题面上没写如无解则输出$impossible$

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef pair<int,int> P;
    #define X first
    #define Y second
    const int MAXN=1e6+10,INF=1<<27;
    P dat[MAXN];
    int l,n,f[MAXN][25],mn[MAXN],res;
    
    bool cmp(P a,P b){return a.Y<b.Y;}
    
    int main()
    {
        scanf("%d%d",&l,&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&dat[i].X,&dat[i].Y);
            if(dat[i].Y<dat[i].X) dat[i].Y+=l;
        }
        sort(dat+1,dat+n+1,cmp);
        
        mn[n+1]=INF;res=INF;
        for(int i=n;i>=1;i--) mn[i]=min(mn[i+1],dat[i].X);
        int cur=1;
        for(int i=1;i<=n;i++)
        {
            while(cur<n && mn[cur+1]-1<=dat[i].Y) cur++;
            if(cur!=i) f[i][0]=cur;
        }
        for(int i=n;i>=1;i--)
            for(int j=1;j<=20;j++)
                f[i][j]=f[f[i][j-1]][j-1];
        
        for(int i=1;i<=n;i++)
        {
            int cur=i,cnt=1;
            for(int j=20;j>=0;j--)
                if(f[cur][j] && dat[f[cur][j]].Y<dat[i].X+l-1) cur=f[cur][j],cnt+=1<<j;
            if(f[cur][0] && dat[cur].Y<dat[i].X+l-1) cur=f[cur][0],cnt++;
            if(dat[cur].Y>=dat[i].X+l-1) res=min(res,cnt);
        }
        if(res==INF) puts("impossible");
        else printf("%d
    ",res);
        return 0;
    }
  • 相关阅读:
    单链表反转
    C++面试题
    堆排序
    1链表:回文链表(leetcode 234)
    深信服社招linux岗面试记录
    腾讯后台开发社招记录(电话面试)
    小米社招ATE岗位记录
    诺基亚社招C++面试记录
    腾讯后台开发社招面试记录
    makefile笔记
  • 原文地址:https://www.cnblogs.com/newera/p/9241728.html
Copyright © 2011-2022 走看看