zoukankan      html  css  js  c++  java
  • bzoj4970 [ioi2004]empodia 障碍段

    Description 

    古数学及哲学家毕氏相信自然之本质为数学。现代生物学家研究生物数列(biosequences)。 生物数数为满足下列条件之 M 个整数所成的数数:
    1: 包含从 0, 1, …, 到 M - 1 的所有数字
    2: 起始数字为 0, 最后一个数字为 M - 1
    ?2:数列中 E+1 不可以紧接在 E 之后
    生物数数的连续子数列称为数段(segments)。如果一个数段的起点为该数段最小的数字, 终点为该数段最大的数字且与起点不是同一个数字,且介于这两个数字之间所有的整数都出现在这个数段中, 则称这个数段为框段(framed 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

    Sample Output

    1
    2 5
     
    正解:单调栈。
    联赛模拟考了这道题。
    讲道理这题并不难,但是全场都在卡$t2$常数,所以写这题的时候还剩十分钟,匆匆暴力了事。
    我们考虑一下一个合法区间的充要条件。
    首先$a[i]-i==a[j]-j$,这个还是比较显然的。
    然后我们记录$lim1[i]$表示以$a[i]$作为最小值,$i$能延伸到的最右端点。
    $lim2[i]$表示以$a[i]$作为最大值,$i$能延伸到的最左端点。
    显然,$lim1[l]>=r,lim2[r]<=l$,然后这两个可以用单调栈求出来。
    然后我们把$a[i]-i$相等的元素分为一组,每次维护一个$lim1[i]$递减的单调栈。
    先把栈顶不合法的弹掉,然后我们就可以直接判断当前元素和栈顶是否可以组成一个合法解。
    得到所有可行解以后,我们还要去掉包含关系的区间,于是对所有区间按照左端点从小到大排序,再做一遍单调栈。
    好像最后一步有更简单的做法,不过懒得改了。
     
     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define N (2000005)
     6 
     7 using namespace std;
     8 
     9 struct data{ int x,y; }ans[N];
    10 struct edge{ int nt,to; }g[N];
    11 
    12 int head[N],lim1[N],lim2[N],st[N],a[N],p[N],n,num,tot,top,Ans;
    13 
    14 il int gi(){
    15   RG int x=0,q=1; RG char ch=getchar();
    16   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    17   if (ch=='-') q=-1,ch=getchar();
    18   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    19   return q*x;
    20 }
    21 
    22 il void insert(RG int from,RG int to){
    23   g[++num]=(edge){head[from],to},head[from]=num; return;
    24 }
    25 
    26 il void solve(){
    27   for (RG int i=1;i<=tot;++i){
    28     while (top && lim1[st[top]]<p[i]) --top;
    29     if (top && lim2[p[i]]<=st[top]) ans[++Ans]=(data){st[top],p[i]};
    30     while (top && lim1[st[top]]<=lim1[p[i]]) --top; st[++top]=p[i];
    31   }
    32   return;
    33 }
    34 
    35 il int cmp(const data &a,const data &b){
    36   if (a.x==b.x) return a.y<b.y; return a.x<b.x;
    37 }
    38 
    39 int main(){
    40 #ifndef ONLINE_JUDGE
    41   freopen("empodia.in","r",stdin);
    42   freopen("empodia.out","w",stdout);
    43 #endif
    44   n=gi(); for (RG int i=1;i<=n;++i) a[i]=gi()+1;
    45   for (RG int i=n;i;--i) insert(n+a[i]-i,i);
    46   for (RG int i=1;i<=n;++i){
    47     while (top && a[st[top]]<a[i]) --top;
    48     lim2[i]=st[top]+1,st[++top]=i;
    49   }
    50   st[top=0]=n+1;
    51   for (RG int i=n;i;--i){
    52     while (top && a[st[top]]>a[i]) --top;
    53     lim1[i]=st[top]-1,st[++top]=i;
    54   }
    55   for (RG int i=0,j;i<=(n<<1);++i){
    56     for (tot=top=0,j=head[i];j;j=g[j].nt) p[++tot]=g[j].to;
    57     if (tot>=2) solve();
    58   }
    59   sort(ans+1,ans+Ans+1,cmp),top=0;
    60   for (RG int i=1;i<=Ans;++i){
    61     while (top && ans[st[top]].y>=ans[i].y) --top;
    62     if (top && ans[st[top]].x==ans[i].x) continue; st[++top]=i;
    63   }
    64   cout<<top<<endl;
    65   for (RG int i=1;i<=top;++i) printf("%d %d
    ",ans[st[i]].x,ans[st[i]].y);
    66   return 0;
    67 }
  • 相关阅读:
    PyTools包罗万象的python工具包
    手撕神经网络实验报告
    数组模拟队列 以及队列的复用(环形队列)
    Sentinel熔断降级
    二维数组与稀疏数组的转换dataStructures
    Sentine熔断降级进阶
    Centos7防火墙以及端口控制
    docker的安装以及使用命令
    ToDesk个人免费 极致流畅的远程协助软件
    typora+PicGo+gitee搭建免费的的床
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7768898.html
Copyright © 2011-2022 走看看