• [cf309E]Sheep


    二分枚举答案,并考虑如下贪心:

    从左到右依次选择区间,并维护未选区间的"右边界"

    记当前位置为$l$,右边界$\le r$的未选区间数为$cnt_{l,r}$(其中$r\in [l,n]$)

    取最小的$r$满足$cnt_{l,r}=|[l,r]|$,将这$cnt_{l,r}$个区间中右端点最小的填在$l$上

    关于上述贪心的正确性,证明如下:

    将所有区间按右端点从小到大排序,并考虑如下引理——

    引理:对于未选区间$x$和已选区间$y$,若$x$在$y$之前,则$x$与$y$有交

    归纳证明,当区间$x$被选择时,对其分类讨论:

    1.若不存在已选区间与$x$有交,结合贪心其必然为第一个未选区间(之前不存在未选区间)

    2.若存在已选区间$y$与$x$有交,任取$x$之前的未选区间$z$,再对其分类讨论:

    (1)若$z$在$y$之前,根据归纳假设$z$与$y$有交,结合贪心此时应选择区间$z$而不是$x$

    (2)若$z$不在$y$之前,注意到$x$之前与$x$有交的区间构成后缀,进而$x$与$z$也有交

    在此基础上,这$cnt_{l,r}$个区间影响范围单调不降,显然可以贪心

    时间复杂度为$o(n^{2}\log n)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 2005
     4 #define fi first
     5 #define se second
     6 int n,P[N],lim[N],cnt[N];
     7 struct Seg{
     8     int l,r,id;
     9     bool operator < (const Seg &n)const{
    10         return r<n.r;
    11     }
    12 }a[N];
    13 bool check(int x,int y){
    14     return (a[x].l<=a[y].r)&&(a[y].l<=a[x].r);
    15 }
    16 bool check(int d){
    17     for(int i=1;i<=n;i++)lim[i]=n;
    18     for(int i=1;i<=n;i++){
    19         memset(cnt,0,sizeof(cnt));
    20         for(int j=1;j<=n;j++)
    21             if ((lim[j])&&(lim[j]<=n))cnt[lim[j]]++;
    22         for(int j=i;j<=n;j++){
    23             cnt[j]+=cnt[j-1];
    24             if (cnt[j]>j-i+1)return 0;
    25         }
    26         for(int j=i;j<=n;j++)
    27             if (cnt[j]==j-i+1){
    28                 for(int k=1;k<=n;k++)
    29                     if ((lim[k])&&(lim[k]<=j)){P[i]=k;break;}
    30                 lim[P[i]]=0;
    31                 for(int k=1;k<=n;k++)
    32                     if (check(k,P[i]))lim[k]=min(lim[k],i+d);
    33                 break;
    34             }
    35     }
    36     return 1;
    37 }
    38 int main(){
    39     scanf("%d",&n);
    40     for(int i=1;i<=n;i++){
    41         scanf("%d%d",&a[i].l,&a[i].r);
    42         a[i].id=i;
    43     }
    44     sort(a+1,a+n+1);
    45     int l=0,r=n;
    46     while (l<r){
    47         int mid=(l+r>>1);
    48         if (check(mid))r=mid;
    49         else l=mid+1;
    50     }
    51     check(l);
    52     for(int i=1;i<=n;i++)printf("%d ",a[P[i]].id);
    53     return 0;
    54 } 
    View Code
  • 相关阅读:
    P1903 [国家集训队]数颜色 / 维护队列 莫对算法
    P1016 旅行家的预算 模拟 贪心
    P3948 数据结构 差分数组
    乘法逆元 模板
    二分法 最大化平均值
    HDU5213 Lucky 莫队算法 容斥定理
    P1083 借教室 差分数组
    发布订阅、redis的配置文件、redis的主从、redis的持久化、
    nosql、redis、性能测试、命令相关、redis的数据类型string、list、hash、set、zset、
    nginx的日志、禁止访问、反向代理、权重、nginx location匹配规则、location分离、WSGI、
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16458642.html
Copyright © 2020-2023  润新知