Salad Bar

POI2014

题意

1.有一个长度为n的字符串,每一位只会是p或j。
2.找到一个子串S,使得不管是从左往右还是从右往左取,都保证每时每刻已取出的p的个数不小于j的个数。
3.求S的最大长度。

1.把p看做+1,把j看做-1

2.设 sum[i]为前缀和

3.如果区间[l,r]要作为答案,必须满足一下条件

条件1:sum[l]~sum[r]-sum[l-1]>=0
(从左往右+1的个数总是不小于-1)
条件2:sum[r]-sum[r]~sum[l]>=0
(从右往左+1的个数总是不小于-1)

4.定义
ml[x]:x点向左第一个大于他的位置
mr[x]:x点向右第一个小于他的位置
单调栈预处理以上数组

5.枚举区间的左端点(左端点必须是p),二分查找最远的右端点

设枚举的左端点为l
根据条件1,右端点的可选区间为[l,mr[l-1]-1]
(因为sum[mr[l]]是第一个小于sum[l-1]的数)二分查找右端点时,
只要[mid,mr[l-1]-1]区间中存在一个mr[t]<l,就表示mid可行
(区间查询可以用ST表O(1)查询)

具体代码

#include<bits/stdc++.h>
using namespace std;
const int M=1000005;
char S[M];
int n,ans,sum[M],ml[M],mr[M];
int mi[M][20],Log[M];
void init(){Log[1]=0;for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1;for(int i=1;i<=n;i++){mi[i][0]=ml[i];}for(int j=1;j<20;j++){for(int i=1;i+(1<<j)-1<=n;i++){mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);}}
}
int query(int L,int R){int k=Log[R-L+1];return min(mi[L][k],mi[R-(1<<k)+1][k]);
}
bool check(int L,int R,int mid){return query(mid,R)<L;
}
int main() {scanf("%d %s",&n,S+1);for(int i=1;i<=n;i++){sum[i]=sum[i-1];if(S[i]=='p')sum[i]++;else sum[i]--;}for(int i=n;i>=0;i--){int x=i+1;while(x<=n&&sum[x]>=sum[i])x=mr[x];mr[i]=x;}for(int i=1;i<=n;i++){int x=i-1;while(x>=1&&sum[x]<=sum[i])x=ml[x];ml[i]=x;}init();for(int i=1;i<=n;i++){if(S[i]=='j')continue;int L=i,R=mr[i-1]-1;while(L<=R){int mid=L+R>>1;if(check(i,mr[i-1]-1,mid)){L=mid+1;if(mid-i+1>ans){ans=mid-i+1;}}else{R=mid-1;}}}printf("%d\n",ans);return 0;
}

POI2014 Salad Bar相关推荐

  1. [POI2014]Salad Bar

    题目大意: 一个长度为$n(n\leq10^6)$的字符串,每一位只会是$p$或$j$.你需要取出一个子串$S$(从左到右或从右到左一个一个取出),使得不管是从左往右还是从右往左取,都保证每时每刻已取 ...

  2. BZOJ3521: [Poi2014]Salad Bar

    维护p-j的前缀和sum[i],那么一段l~r合法的充要条件是sum[l]<=sum[l~r],sum[r]>=sum[l~r],即中间的所有sum都>=sum[l],<=su ...

  3. bzoj 3521: [Poi2014]Salad Bar

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3521 POI的题果然都有一些很精妙的O(n)O(n)O(n)做法 带log的比较简单,这里就 ...

  4. P3564 [POI2014]BAR-Salad Bar(ST表 + 二分)

    P3564 [POI2014]BAR-Salad Bar 给定一个长度为nnn的数组,里面元素只有111跟−1-1−1,问选出一个长度为lenlenlen的区间使得,这个区间的前缀和时刻大于零,后缀和 ...

  5. 【思维题 单调栈】loj#2430. 「POI2014」沙拉餐厅 Salad Bar

    t老师的做法好神-- 题目描述 桌面上有 n 个水果,分别是苹果和橘子.Bytea需要从水果中选择连续的一个区间,并从左到右或从右到左拿水果,且过程中橘子的数量必须始终不小于苹果的数量.求最长的区间大 ...

  6. 【LOJ】#2430. 「POI2014」沙拉餐厅 Salad Bar

    题解 波兰人的j是苹果,p是橘子 还真是跟中国过不去啊= =写的时候很难受 我们先求出每个点作为起点,能延伸到的最大长度,这个可以处理成前缀和,查询一下区间最小值是不是小于0,用st表实现,如果区间最 ...

  7. POI2014Salad Bar

    POI2014 Salad Bar 这道题的大意就是给你一个字符串,里面只含有p和j,求一个最长的子串,使得从左边开始,p的个数一直比j多,从右边开始也一样. 这道题的话,一开始想歪了,就先对每个字符 ...

  8. POI 2014 切题记

    POI 2014 Salad Bar Description: 有一个长度为nnn的字符串,每一位只会是ppp或jjj.你需要取出一个子串SSS(从左到右或从右到左一个一个取出),使得不管是从左往右还 ...

  9. 8000 sentences of oral English(four)

    第四章 表现感情的短句 (16)高兴时 ●欣喜 How's your newhome? --I'm happy. 我很高兴!我很幸福! I'm ecstatic. 狂喜 I'm thrilled. 我 ...

最新文章

  1. mysql 挂掉 无法启动_mysql-配置 - MySQL错误,时不时自动挂掉,无法启动
  2. 怎么配置搭建Nginx网站服务器
  3. Django View使用装饰器捕获数据库连接异常
  4. 算法心经:数学的应用:概率的应用
  5. 【-】WebKit Layout (布局)
  6. jms、amqp、mqtt区别与联系
  7. linux下ssh通过公钥登录服务器
  8. C语言 显示器键盘io
  9. lucene全文检索mysql教程_对于数据库里的多张表怎么利用lucene等实现全文检索
  10. springboot security 安全
  11. Android酷炫有用的开源框架
  12. 如何成为更高级别的iOS开发工程师?
  13. 物联网云平台系统设计
  14. 关于数字证书链的一点认知
  15. 六十六条经典禅语名句
  16. 揭密巴西Banrisul银行网站遭遇5小时劫持的原因
  17. Unity流水账14:GL、Graphics及CommandBuffer
  18. C语言实现实数和复数矩阵及其各种运算(一)
  19. Django连接MySQL对数据进行网页展示
  20. 数字IC设计随笔之七(TCL脚本编程入门)

热门文章

  1. 7-6 厘米换算英尺英寸
  2. 全球与中国心里健康平台市场现状及未来发展趋势2022-2028
  3. web前端之CSS3
  4. 开源真的在蚕食整个世界吗
  5. java毕业设计大学生二手物品交易网站演示记录2021Mybatis+系统+数据库+调试部署
  6. coda2怎么连接mysql_Coda 2.7.7 - Web管理通用工具包
  7. 服务搭建篇(七) Elasticsearch单节点部署以及多节点集群部署
  8. C++注释的几种方法
  9. 黑马毕向东Java课程笔记(day20-1——20-17)IO流:File类及相关方法、递归、递归的相关练习、Properties、PrintWriter类与PrintStream类、合并流与切割流
  10. 82.Hive SQL插入动态分区的异常分析