BZOJ4970 IOI2004 empodia障碍段

4970: [ioi2004]empodia 障碍段

Time Limit: 10 Sec  Memory Limit: 128 MB

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的复数形)。

Input

第一行为单一整数M,代表生物数列的长度。 
生物数列中的数字依序出现在接下来的 M 行,每一行有一个整数
M≤1100000

Output

第一行为一整数H,代表该生物数列中的障碍段的个数。
接下来的 H 行,将每一个障碍段,依照起点在原输入生物数列中出现的顺序,依序输出。
每行以2个整数A 与 B 代表一个障碍段并以一个空白分开
原输入生物数列第 A 个元素为该障碍段之起点,而第 B 个元素为该障碍段之终点

Sample Input

8
0
3
5
4
6
2
1
7

Sample Output

1
2 5
 
  Nick大佬出的联赛模拟题……这已经不是第一个在联赛模拟上出IOI题的人了?不过可能是我唯一能切的题吧,还是在机缘巧合之下。
  放在二维平面上就是一个正方形网格,然后枚举左下角,看怎么快速计算右上角。
  首先左下角的点是作为矩阵的最小值的,所以可以通过一次单调栈从右往左找到右边界最值。
  其次,右上角的点作为矩阵的最大值,一定在从右往左递减的单调栈_2里。因为单调栈对应关系是唯一的,所以可以把它看成一棵树,从右往左连边,根节点为(n,n),答案就只有可能出现在某节点的祖先链上。
  对应的式子是A[i]-A[j]=i-j,即A[i]-i=A[j]-j。我们在单调栈_2构成的树上dfs,维护一下一条链上的信息,用一个桶记录一下A[i]-i最前面的位置就可以了。
  最后得到了不超过n个矩阵(区间),去重去包含就是很简单的事情了。
#include <map>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define rg register
#define FILE "empodia"
using namespace std;

const int N = 1100010;
int n,A[N],sta[N],nxt_1[N],nxt_2[N],Ans,bin[N<<1],R[N];
vector<int>G[N];

inline int gi(){
  rg int x=0,res=1;rg char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-')res^=1;ch=getchar();}
  while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
  return res?x:-x;
}

inline void link(int u,int v){
  G[u].push_back(v);
}

inline void getnxt_1(rg int tp=0){
  sta[0]=n+1;
  for(rg int i=n;i>=1;--i){
    while(tp && A[sta[tp]]<A[i])tp--;
    nxt_1[i]=sta[tp];sta[++tp]=i;
    link(nxt_1[i],i);
  }
}

inline void getnxt_2(rg int tp=0){
  sta[0]=n+1;
  for(rg int i=n;i>=1;--i){
    while(tp && A[sta[tp]]>A[i])tp--;
    nxt_2[i]=sta[tp];sta[++tp]=i;
  }
}

inline void dfs(int x){
  int g=A[x],qt=bin[g];
  if(bin[g]<=nxt_2[x])R[x]=bin[g];
  bin[g]=x;
  for(int i=0,j=G[x].size();i<j;i++)
    dfs(G[x][i]);
  bin[g]=qt;
}

int main(){
  freopen(FILE".in","r",stdin);
  freopen(FILE".out","w",stdout);
  n=gi();memset(bin,127,sizeof(bin));
  for(rg int i=1;i<=n;++i)A[i]=gi()+1;
  getnxt_1();getnxt_2();
  memset(R,127,sizeof(R));
  for(int i=1;i<=n;++i)A[i]=A[i]-i+n;
  dfs(n);
  for(int i=n,Mx=R[0];i>=1;--i){
    if(R[i]>Mx)R[i]=R[0];
    Mx=min(Mx,R[i]);
  }
  for(int i=1;i<=n;++i)if(R[i]<=n)Ans++;
  printf("%d
",Ans);
  for(int i=1;i<=n;++i)
    if(R[i]<=n)printf("%d %d
",i,R[i]);
  fclose(stdin);fclose(stdout);
  return 0;
}
障碍段
原文地址:https://www.cnblogs.com/fenghaoran/p/7768653.html