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

  • 相关阅读:
    平衡二叉树之RB树
    平衡二叉树之AVL树
    实现哈希表
    LeetCode Median of Two Sorted Arrays
    LeetCode Minimum Window Substring
    LeetCode Interleaving String
    LeetCode Regular Expression Matching
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    LeetCode Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/antiquality/p/9838566.html
Copyright © 2011-2022 走看看