zoukankan      html  css  js  c++  java
  • bzoj 4970: [ioi2004]empodia 障碍段

    Description

    古数学及哲学家毕氏相信自然之本质为数学。现代生物学家研究生物数列(biosequences)。 生物数数为满足下列
    条件之 M 个整数所成的数数:
    1: 包含从 0, 1, …, 到 M - 1 的所有数字
    2: 起始数字为 0, 最后一个数字为 M - 1
    ?2:数列中 E+1 不可以紧接在 E 之后
    生物数数的连续子数列称为数段(segments)。如果一个数段的起点为该数段最小的数字, 终点为该数段最大的数
    字且与起点不是同一个数字,且介于这两个数字之间所有的整数都出现在这个数段中, 则称这个数段为框段(frame
    d interval),如果框段中并不包含题名小的框段,则称之为障碍段(empodio)。以(0,3,5,4,6,2,1,7)这个生物数
    列为例。 整个生物数?是一个框段, 可是它包含了另外一框段 (3,5,4,6) ,因此该生物数列是障碍段。而框段 (
    3,5,4,6) 并不包含任何更短的框段所以它是一个障碍段,而且是此生物数列中唯一的障碍段。请写一个程序, 在
    输入生物数列后, 输出所有的障碍段 (empodia 为 empodio的复数形)。

    solution

    这题比较巧,我们首先意识到,点对一定满足 (a[i]-a[j]=i-j),即 (a[i]-i=a[j]-j),然后我们枚举等式的值,抠出满足等式的条件的点,然后拿这些点做
    然后是一个套路,求出 (f[i]) 表示这个点做为最大值能够往左边延伸到的最远位置, (g[i]) 表示这个点做为最小值能够往右边延伸到的最远距离,然后满足二维偏序即可
    对于点对 ((i,j))(f[j]<=i)(g[i]>=j) 即可满足条件,因为要满足不存在区间包含关系,所以可以维护 (g[i]) 的单调栈即可,我们要取的 (i) 要尽量小

    #include <algorithm>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <cstdlib>
    #define il inline
    #define RG register
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=1100005;
    il int gi(){
      RG int str=0;RG char ch=getchar();
      while(ch>'9' || ch<'0')ch=getchar();
      while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
      return str;
    }
    
    int st[N],top=0,f[N],g[N],n,a[N],head[N*2],nxt[N],to[N],num=0;
    int m=0,b[N],bel[N];
    void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    void priwork(){
       for(int i=1;i<=n;i++){
          while(top && a[i]>a[st[top]])top--;
          if(top)f[i]=st[top]+1;
          st[++top]=i;
       }
       top=0;
       for(int i=n;i>=1;i--){
          while(top && a[i]<a[st[top]])top--;
          if(top)g[i]=st[top]-1;
          st[++top]=i;
       }
       for(int i=1;i<=n;i++)if(g[i]==0)g[i]=n+1;
       for(int i=n;i>=1;i--)link(a[i]-i+n,i);
    }
    
    int cnt=0;
    void solve(){
       top=0;
       for(int i=1;i<=m;i++){
          while(top && g[st[top]]<b[i])top--;
          if(top && st[top]>=f[b[i]])bel[b[i]]=st[top],cnt++;
          st[++top]=b[i];
       }
    }
    
    struct node{
       int l,r;
       bool operator <(const node &pr)const{return l<pr.l;}
    }e[N];
    void work()
    {
      scanf("%d",&n);
      for(int i=1;i<=n;i++)a[i]=gi(),a[i]++;
      priwork();
      for(int i=0;i<=n+n;i++){
         m=0;
         for(int j=head[i];j;j=nxt[j])
            b[++m]=to[j];
         if(m<2)continue;
         solve();
      }
      int tot=0;
      for(int i=1;i<=n;i++)
         if(bel[i])e[++tot].l=bel[i],e[tot].r=i;
      sort(e+1,e+tot+1);
      top=0;
      for(int i=1;i<=tot;i++)
         if(e[i].r<=e[top].r)e[top]=e[i];
         else e[++top]=e[i];
      printf("%d
    ",top);
      for(int i=1;i<=top;i++)
         printf("%d %d
    ",e[i].l,e[i].r);
    }
    
    int main()
    {
      work();
      return 0;
    }
    
    
  • 相关阅读:
    GHOJ 683 小球
    GHOJ 682 图的m着色问题
    GHOJ 681 最佳调度问题
    YBT 最长公共子上升序列
    YBT 数的划分
    Educational Codeforces Round 68 (Rated for Div. 2) C
    马里奥项目中对象直接通讯小结
    Educational Codeforces Round 67 (Rated for Div. 2) C
    19新疆省赛总结
    Codeforces Round #560 div3 (C,D)
  • 原文地址:https://www.cnblogs.com/Hxymmm/p/7767963.html
Copyright © 2011-2022 走看看