Solution

首先审清题意, 这里要求的是子串而不是子序列...

我们考虑用1表示p, -1表示j. 用sum[i]表示字符串前\(i\)的前缀和. 则我们考虑一个字符串\([L, R]\)有什么要求: \(\forall x \in [L, R]\)满足\(sum[x] \ge sum[L - 1]\).

我们分别从前往后和从后往前求出以每个位置为开头的最长合法子串, 然后扔进树状数组里面查询即可.

至于怎么求以每个位置为开头最长合法子串, 我们考虑用一个单调栈来维护: 从前往后扫每个位置, 假如当前位置的\(sum\)小于栈顶的\(sum\)则弹栈, 并把以栈顶为开头的最长合法子串的末尾设为当前位置的前一位. 弹栈结束后, 插入当前位置即可.

#include <cstdio>
#include <algorithm>
#include <cstring> using namespace std;
const int N = (int)1e6, INF = (int)2e9;
int n;
struct record
{
int L, R;
inline int operator <(const record &a) const {return R < a.R;}
}rec[N + 1];
struct segmentTree
{
int mn[N << 2];
inline segmentTree() {memset(mn, 127 ,sizeof(mn));}
void insert(int u, int L, int R, int pos)
{
mn[u] = min(mn[u], pos);
if(L == R) return;
if(pos <= L + R >> 1) insert(u << 1, L, L + R >> 1, pos);
else insert(u << 1 | 1, (L + R >> 1) + 1, R, pos);
}
inline void insert(int pos) {insert(1, 1, n, pos);}
int query(int u, int L, int R, int pos)
{
if(L >= pos) return mn[u];
int mid = L + R >> 1;
if(pos <= mid) return min(query(u << 1, L, L + R >> 1, pos), query(u << 1 | 1, (L + R >> 1) + 1, R, pos));
else return query(u << 1 | 1, (L + R >> 1) + 1, R, pos);
}
inline int query(int pos) {return query(1, 1, n, pos);}
}seg;
struct binaryIndexedTree
{
int mx[N + 1];
inline binaryIndexedTree() {memset(mx, -1, sizeof(mx));}
inline void insert(int pos, int x)
{
for(int i = pos; i <= n; i += i & - i)
mx[i] = max(mx[i], x);
}
inline int query(int pos)
{
int res = -1;
for(int i = pos; i; i -= i & - i) res = max(res, mx[i]);
return res;
}
}BIT;
int main()
{ #ifndef ONLINE_JUDGE freopen("bar.in", "r", stdin);
freopen("bar.out", "w", stdout); #endif scanf("%d\n", &n);
static int a[N + 1];
for (int i = 1; i <= n; ++ i) a[i] = getchar() == 'p' ? 1 : -1;
static int stk[N + 1], sum[N + 2];
int tp = 0; stk[tp ++] = 0;
sum[0] = 0; for (int i = 1; i <= n; ++ i) sum[i] = sum[i - 1] + a[i]; sum[n + 1] = - INF;
static int f[N + 1];
for (int i = 1; i <= n + 1; ++ i)
{
while (tp && sum[i] < sum[stk[tp - 1]]) f[stk[tp - 1] + 1] = i - 1, -- tp;
stk[tp ++] = i;
}
for(int i = 1; i <= n; ++ i) rec[i].L = i, rec[i].R = f[i];
tp = 0; stk[tp ++] = n + 1;
sum[n + 1] = 0; for(int i = n; i; -- i) sum[i] = sum[i + 1] + a[i]; sum[0] = - INF;
for(int i = n; ~ i; -- i)
{
while(tp && sum[i] < sum[stk[tp - 1]]) f[stk[tp - 1] - 1] = i + 1, -- tp;
stk[tp ++] = i;
}
sort(rec, rec + n + 1);
int ans = 0;
/* for(int i = 1, p = 1; i <= n; ++ i)
{
for(; rec[p].R <= i; ++ p) seg.insert(rec[p].L);
int cur = seg.query(f[i]);
if(cur > i) continue;
else ans = max(ans, i - cur + 1);
} */
for(int i = 1, p = 1; i <= n; ++ i)
{
for(; p <= rec[i].R; ++ p) BIT.insert(f[p], p);
int cur = BIT.query(rec[i].L);
if(cur >= rec[i].L) ans = max(ans, cur - rec[i].L + 1);
}
printf("%d\n", ans);
}

2016集训测试赛(二十六)Problem A: bar的更多相关文章

  1. 2016北京集训测试赛(十六)Problem C: ball

    Solution 这是一道好题. 考虑球体的体积是怎么计算的: 我们令\(f_k(r)\)表示\(x\)维单位球的体积, 则 \[ f_k(1) = \int_{-1}^1 f_{k - 1}(\sq ...

  2. 2016北京集训测试赛(十六)Problem B: river

    Solution 这题实际上并不是构造题, 而是一道网络流. 我们考虑题目要求的一条路径应该是什么样子的: 它是一个环, 并且满足每个点有且仅有一条出边, 一条入边, 同时这两条边的权值还必须不一样. ...

  3. 2016北京集训测试赛(十六)Problem A: 任务安排

    Solution 这道题告诉我们, 不能看着数据范围来推测正解的时间复杂度. 事实证明, 只要常数足够小, \(5 \times 10^6\)也是可以跑\(O(n \log n)\)算法的!!! 这道 ...

  4. 【2016北京集训测试赛(十六)】 River (最大流)

    Description  Special Judge Hint 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. 题解 题目大意:给定两组点,每组有$n$个点,有若干条跨组 ...

  5. 2016集训测试赛(十九)Problem C: 无聊的字符串

    Solution 傻X题 我的方法是建立后缀后缀树, 然后在DFS序列上直接二分即可. 关键在于如何得到后缀树上每个字符对应的字节点: 我们要在后缀自动机上记录每个点在后缀树上对应的字母. 考虑如何实 ...

  6. 2016集训测试赛(十九)Problem A: 24点大师

    Solution 这到题目有意思. 首先题目描述给我们提供了一种非常管用的模型. 按照题目的方法, 我们可以轻松用暴力解决20+的问题; 关键在于如何构造更大的情况: 我们发现 \[ [(n + n) ...

  7. 2016集训测试赛(十八)Problem C: 集串雷 既分数规划学习笔记

    Solution 分数规划经典题. 话说我怎么老是忘记分数规划怎么做呀... 所以这里就大概写一下分数规划咯: 分数规划解决的是这样一类问题: 有\(a_1, a_2 ... a_n\)和\(b_1, ...

  8. 2016北京集训测试赛(十)Problem A: azelso

    Solution 我们把遇到一个旗子或者是遇到一个敌人称为一个事件. 这一题思路的巧妙之处在于我们要用\(f[i]\)表示从\(i\)这个事件一直走到终点这段路程中, \(i\)到\(i + 1\)这 ...

  9. 2018.7.31 Noip2018模拟测试赛(十六)

     日期: 七月最后一天  总分: 300分  难度: 提高 ~ 省选  得分: 30分(少的可怜) 我太弱了:(题目目录) T1:Mushroom追妹纸 T2:抵制克苏恩 T3:美味 失分分析:(QA ...

随机推荐

  1. Android 自定义debug.keystore

    场景分析: 有时候,我们要使用第三方的服务,需要提供自己的包名以及keystore的sha1值,比如微信支付,百度地图,都需要包名和keystore的sha1值作为唯一标识.这时候我们测试的时候,如果 ...

  2. Linux程序编辑器习题汇总

    简答题部分: 1.我用vi开启某个档案后,要在第34行向右移动15个字符,应该在一般模式中下达什么指令? (1)先按下34G到34行:(2)再按下[l5+向右键],或[l5l]亦可! 2.在vi开启的 ...

  3. Aptana Studion出现 duplicate location重复定位报错

    1.下载SVN的时候出现报错 duplicate location 2.点击“available software sites”查看已可用的软件网站 3.在这里可以查看到SVN,勾选SVN复选框,点击 ...

  4. 第1章 HTML基础

    1.1 HTML概述 1.1.1 什么是HTML HTML(Hyper Text Markup Language,超 文本 标记 语言)是纯文本类型的语言,它是Internet上用于编写网页的主要语言 ...

  5. copy & deepcopy

    1 import copy 2 3 字典参照列表结论,看是否有深层嵌套. 4 a = {'name':1,'age':2} 5 b = a 6 a['name'] = 'ff' 7 print(a) ...

  6. php 实现栈与队列

    <?php class queueOp{ /* * 队尾入队 * Return:处理之后队列的元素个数 */ public function tailEnquque($arr,$val){ re ...

  7. 【JSOI2008】星球大战 并查集

    题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧 ...

  8. python矩阵和向量的转置问题

    numpy有很多方法进行转置,这里由于时间和精力限制(主要是我实在比较懒,有一个基本上一直能使的,就懒得看其他的了),其他方法我没研究,这里我总结的东西,如果有问题,欢迎各路大佬拍砖 一.创建矩阵: ...

  9. Java学习5之接口

    接口不是类,而是一个特殊的名称,使用interface关键字.子类可以实现多个接口. 接口实现: public class Child extends Parent implements Interf ...

  10. java之ArrayList.add

    ArrayList添加 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! ele ...