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\n",top);
  for(int i=1;i<=top;i++)
     printf("%d %d\n",e[i].l,e[i].r);
}

int main()
{
  work();
  return 0;
}

posted @ 2017-11-01 19:01  Hxymmm  阅读(255)  评论(0编辑  收藏  举报