zoukankan      html  css  js  c++  java
  • 【思维题 单调栈】loj#2430. 「POI2014」沙拉餐厅 Salad Bar

    t老师的做法好神……

    题目描述

    桌面上有 n 个水果,分别是苹果和橘子。Bytea需要从水果中选择连续的一个区间,并从左到右或从右到左拿水果,且过程中橘子的数量必须始终不小于苹果的数量。求最长的区间大小。

    输入格式

    第一行一个整数 n($1 le n le 100000$),表示水果个数。 接下来一行共有 n 个字符$a_1, a_2, ..., a_n (a_i in {j,p})$,分别表示苹果和橘子(波兰语)。

    输出格式

    输出一行共一个数字,表示最长的区间大小。

    样例输入

    6
    jpjppj

    样例输出

    4

    数据范围与提示

    对于 $20\%$ 的数据,$n le 1000$.
    对于 $50\%$ 的数据,$n le 10000$.
    对于所有数据,$1 le n le 100000$.


    题目分析

    做法来源:「LOJ #2430」「POI2014」沙拉餐厅 Salad Baralad Bar

    令$d_i$为$sum_{x=1}^{i}{[s_x=='p']-[s_x=='j']}$,那么合法区间的充要条件就是$i in (l,r), d_l le d_i le d_r$。(这个转化超级妙的)

    那么用单调栈找到离以$i$为右端点区间的最近$l$,满足$d_l>d_i$,于是左端点就是$[l+1,r]$间$d_i$最小值的位置。

    所以在单调栈过程中顺带维护以$i$为起点区间最小值的位置。有个小细节就是利用$f[0]=0$这么一个初值,来做相当于哨兵节点一样的作用,避免了$d_i<0$被判断合法。

    感觉我单调栈并不熟练…… 

     1 #include<bits/stdc++.h>
     2 const int maxn = 1000035;
     3 
     4 int n,ans,cnt,top,stk[maxn],d[maxn],f[maxn];
     5 char s[maxn];
     6 
     7 int main()
     8 {
     9     scanf("%d%s",&n,s+1);
    10     for (int i=1; i<=n; i++)
    11     {
    12         d[i] = d[i-1]+(s[i]=='p'?1:-1);
    13         while (top&&stk[top] <= d[i])
    14         {
    15             if (d[f[top-1]] > d[f[top]]) f[top-1] = f[top];
    16             top--;
    17         }
    18         if (d[f[top]] <= d[i]) ans = std::max(ans, i-f[top]);
    19         stk[++top] = d[i], f[top] = i;
    20     }
    21     printf("%d
    ",ans);
    22     return 0;
    23 }

    END

  • 相关阅读:
    CF785E Anton and Permutation
    P4054 [JSOI2009]计数问题
    P4396 [AHOI2013]作业
    AD PCB中各层的含义
    AD21 使用手册 快捷键(二)
    AD 汉化和界面恢复
    AD21 使用手册 快捷键(一)
    TINA-TI 安装
    B站下载 视频
    restful-work基本组件
  • 原文地址:https://www.cnblogs.com/antiquality/p/9838566.html
Copyright © 2011-2022 走看看