[SCOI2015]国旗计划[Wf2014]Surveillance

[SCOI2015]国旗计划

A国正在开展一项伟大的计划——国旗计划。这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈。这
项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了N名优秀的边防战上作为这
项计划的候选人。
A国幅员辽阔,边境线上设有M个边防站,顺时针编号1至M。每名边防战士常驻两个边防站,并且善于
在这两个边防站之间长途奔袭,我们称这两个边防站之间的路程是这个边防战士的奔袭区间。n名边防战士
都是精心挑选的,身体素质极佳,所以每名边防战士的奔袭区间都不会被其他边防战士的奔袭区间所包含。
现在,国十安全局局长希望知道,至少需要多少名边防战士,才能使得他们的奔袭区间覆盖全部的边境线,
从而顺利地完成国旗计划。不仅如此,安全局局长还希望知道更详细的信息:对于每一名边防战士,在他必
须参加国旗计划的前提下,至少需要多少名边防战士才能覆盖全部边境线,从而顺利地完成国旗计划。
题解
如果是一条链的情况,就可以直接贪心做了。
但这是个环,根据国际惯例,断环为链。
分析一下,我们可以把一条边拆成两个。
对于l<r的情况、

 

对于l>r的情况。

注意,后面那一条线段不要漏掉,否则会WA一个点。

于是就可以愉快的倍增了,对于每一个点都倍增一遍。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 400002
using namespace std;
typedef unsigned int ll;
ll len,b[N<<1];
int n,p[21][N],top,tag[N<<1],an[N];
inline int rd(){
    int x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
struct node{
    ll l,r;int id;
    bool operator <(const node &b)const{return r<b.r;}
}a[N];
int main(){
    n=rd();len=rd();int haha=n;
    for(int i=1;i<=n;++i){
      a[i].l=rd(),a[i].r=rd();a[i].id=i;
      if(a[i].r<a[i].l){
        a[i].r+=len;
        a[++haha].l=a[i].l+len;a[haha].r=len*2;a[haha].id=haha;
      }
      else{
        a[++haha].l=a[i].l+len;a[haha].r=a[i].r+len;a[haha].id=haha;
        b[++top]=a[i].l+len;b[++top]=a[i].r+len;    
      }
        b[++top]=a[i].l;b[++top]=a[i].r;
    }
    b[++top]=len;
    sort(a+1,a+haha+1);sort(b+1,b+top+1);
    top=unique(b+1,b+top+1)-b-1;
    for(int i=1;i<=haha;++i){
        int x=lower_bound(b+1,b+top+1,a[i].l)-b;
        if(a[i].r>a[tag[x]].r)tag[x]=i;
    }
    for(int i=2;i<=top;++i)if(a[tag[i-1]].r>a[tag[i]].r)tag[i]=tag[i-1];
    for(int i=1;i<=haha;++i){
        int x=lower_bound(b+1,b+top+1,a[i].r)-b;
        p[0][i]=tag[x];
    }
    for(int i=1;i<=20;++i)
      for(int j=1;j<=haha;++j)p[i][j]=p[i-1][p[i-1][j]];
    for(int i=1;i<=haha;++i){
        if(i>n)continue;
        ll ans=2e9,t=a[i].l+len,num=0;
        int now=i;
        for(int j=20;j>=0;--j){
            int x=p[j][now];
            if(!x)continue;
            if(a[x].r>=t)ans=min(ans,num+(1<<j));
            else now=x,num+=(1<<j);
        }
        an[a[i].id]=ans+1;
    }
    for(int i=1;i<=n;++i)printf("%u ",an[i]);
    return 0;
}

[Wf2014]Surveillance

给你一个长度为len的环,以及n个区间,要你选择尽量少的区间,使得它们完全覆盖整个环。问最少要多少个区间。

和上一题基本相同,但是略有区别,这道题要求覆盖,上一道题还要求相邻两条线段有交。

但是这道题我们就可以不用拆线段了,因为我们从每个点都倍增一遍一定能找到最优解。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 1000002
using namespace std;
typedef unsigned int ll;
ll len,b[N*3];
int n,p[22][N],top,tag[N*3],an[N];
inline int rd(){
    int x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
struct node{
    ll l,r;int id;
    bool operator <(const node &b)const{return r<b.r;}
}a[N];
int main(){
      len=rd();    n=rd();
    for(int i=1;i<=n;++i){
      a[i].l=rd(),a[i].r=rd();a[i].id=i;
      if(a[i].r<a[i].l)a[i].r+=len;
       b[++top]=a[i].l;b[++top]=a[i].r;b[++top]=a[i].l-1;
    }
    sort(a+1,a+n+1);sort(b+1,b+top+1);
    top=unique(b+1,b+top+1)-b-1;
    for(int i=1;i<=n;++i){
        int x=lower_bound(b+1,b+top+1,a[i].l)-b;
        if(a[i].r>a[tag[x-1]].r)tag[x-1]=i;
    }
    for(int i=1;i<=top;++i)if(a[tag[i-1]].r>a[tag[i]].r)tag[i]=tag[i-1];
    for(int i=1;i<=n;++i){
        int x=lower_bound(b+1,b+top+1,a[i].r)-b;
        p[0][i]=tag[x];//cout<<a[i].r<<" "<<a[tag[x]].r<<endl;
    }
    for(int i=1;i<=21;++i)
      for(int j=1;j<=n;++j)p[i][j]=p[i-1][p[i-1][j]];
      ll an=2e9;
    for(int i=1;i<=n;++i){
        if(a[i].r-a[i].l+1==len)an=1;
        ll ans=2e9,t=a[i].l+len,num=0;
        int now=i;
        for(int j=21;j>=0;--j){
            int x=p[j][now];//if(j==21)cout<<a[x].r<<" "
            if(!x)continue;
            if(a[x].r>=t-1)ans=min(ans,num+(1<<j));
            else now=x,num+=(1<<j);
        }
        an=min(an,ans+1);
    }
   if(an==2e9)puts("impossible");else cout<<an;
    return 0;
}

转载于:https://www.cnblogs.com/ZH-comld/p/10260417.html

中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整数NN和KK,表示幼儿园里的小朋友数量和要满足的要求数量。接下来的KK行表示小朋友们的要求,每行有三个数字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果数量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果数量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果数量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.csdn.net/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.csdn.net/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值