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\n",Ans);
  for(int i=1;i<=n;++i)
    if(R[i]<=n)printf("%d %d\n",i,R[i]);
  fclose(stdin);fclose(stdout);
  return 0;
}
障礙段
相關文章
相關標籤/搜索