4384: [POI2015]Trzy wieże

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 217  Solved: 61
[Submit][Status][Discuss]

Description

给定一个长度为n的仅包含'B'、'C'、'S'三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同。

Input

第一行包含一个正整数n(1<=n<=1000000),表示字符串的长度。
第二行一个长度为n的字符串。

Output

包含一行一个正整数,即最长的满足条件的子串的长度。

Sample Input

9
CBBSSBCSC

Sample Output

6

HINT

选择BSSBCS这个子串。

Source

[Submit][Status][Discuss]

分析

OTZ Claris

OTZ LincHpin

OTZ MirrorGray

——下面开始正文——

子串只包含一种字符的情况特殊处理,一遍扫描就可以了。

首先将字符串转换称数字串,分别用0,1,2替代B,C,S。

设sum[i][j]表示前i(0<=i<=n)个数字中j(0<=j<=2)的出现次数,则题目要求可以翻译如下

选取一段[lt + 1, rt],满足:

sum[rt][0] - sum[lt][0] != sum[rt][1] - sum[lt][1]

sum[rt][0] - sum[lt][0] != sum[rt][2] - sum[lt][2]

sum[rt][1] - sum[lt][1] != sum[rt][2] - sum[lt][2]

从Claris大神那里学到的机智转换——通过交换等式两边的元素,将lt和rt分离。

sum[rt][0] - sum[rt][1] != sum[lt][0] - sum[lt][1]

sum[rt][0] - sum[rt][2] != sum[lt][0] - sum[lt][2]

sum[rt][1] - sum[rt][2] != sum[lt][1] - sum[lt][2]

这看起来就神清气爽多了,问题就转换成了——

每个点上有一个三元组(x,y,z),以及一个id,求对于每个点来说,和它的三元组完全不同的id相距最远的点。

将(x,y,z,id)按照x从小到大排序,这样就可以保证x的不同了。

然后把y当作树状数组下标维护id的最大、最小值,这样查询的时候避开自己y的地方就可以保证y也不同了。

可以z还可能相同,所以要维护次优解,且强制最优解和次优解的z不同。当最优解的z和当前点的z相同时,选择用次优解来更新即可。这样就保证z也不同了。

然而并不清楚Claris大神是怎么用64行写完的,但也不代表我写200+行就有多麻烦,至少不是很费脑子(才怪)。

代码

 #include <bits/stdc++.h>

 const int N = ;
const int inf = 1e9 + ; int n, m; int h[N]; char s[N]; int sum[]; int answer; struct Point
{
int id, x, y, z; Point(void) {};
Point(int i, int a, int b, int c)
{
id = i;
x = a;
y = b;
z = c;
} friend bool operator < (const Point &a, const Point &b)
{
return a.x < b.x;
}
}p[N]; struct Pair
{
int val, pos; Pair(void) {}; Pair(int a, int b)
{
val = a;
pos = b;
} friend bool operator ^ (const Pair &a, const Pair &b)
{
return a.pos != b.pos;
} friend bool operator < (const Pair &a, const Pair &b)
{
return a.val < b.val;
} friend bool operator > (const Pair &a, const Pair &b)
{
return a.val > b.val;
}
}; struct MinMax
{
Pair min0;
Pair min1;
Pair max0;
Pair max1; MinMax(void)
{
min0 = Pair(inf, -inf);
min1 = Pair(inf, -inf);
max0 = Pair(-inf, -inf);
max1 = Pair(-inf, -inf);
} MinMax(int val, int pos)
{
min0 = max0 = Pair(val, pos);
min1 = Pair(inf, -inf);
max1 = Pair(-inf, -inf);
} friend MinMax operator + (const MinMax &a, const MinMax &b)
{
MinMax r; if (a.min0 < b.min0)
{
r.min0 = a.min0;
if (a.min1 < b.min0)
r.min1 = a.min1;
else if (a.min0 ^ b.min0)
r.min1 = b.min0;
else if (a.min1 < b.min1)
r.min1 = a.min1;
else
r.min1 = b.min1;
}
else
{
r.min0 = b.min0;
if (b.min1 < a.min0)
r.min1 = b.min1;
else if (a.min0 ^ b.min0)
r.min1 = a.min0;
else if (b.min1 < a.min1)
r.min1 = b.min1;
else
r.min1 = a.min1;
} if (a.max0 > b.max0)
{
r.max0 = a.max0;
if (a.max1 > b.max0)
r.max1 = a.max1;
else if (a.max0 ^ b.max0)
r.max1 = b.max0;
else if (a.max1 > b.max1)
r.max1 = a.max1;
else
r.max1 = b.max1;
}
else
{
r.max0 = b.max0;
if (b.max1 > a.max0)
r.max1 = b.max1;
else if (a.max0 ^ b.max0)
r.max1 = a.max0;
else if (b.max1 > a.max1)
r.max1 = b.max1;
else
r.max1 = a.max1;
} return r;
}
}; struct BIT
{
MinMax tree[N]; int lowbit(int x)
{
return x & -x;
} MinMax query(int p)
{
MinMax r; while (p)
{
r = r + tree[p];
p -= lowbit(p);
} return r;
} void insert(int p, MinMax v)
{
while (p <= m)
{
tree[p] = tree[p] + v;
p += lowbit(p);
}
}
}lt, rt; signed main(void)
{
scanf("%d%s", &n, s + ); for (int i = , j = ; i <= n; ++i)
{
if (s[i] == s[i - ])
answer = std::max(answer, ++j);
else
answer = std::max(answer, j = );
} for (int i = ; i <= n; ++i)
{
switch (s[i])
{
case 'B': ++sum[]; break;
case 'C': ++sum[]; break;
case 'S': ++sum[]; break;
} p[i] = Point(
i,
sum[] - sum[],
sum[] - sum[],
sum[] - sum[]
); h[i] = p[i].y;
} p[++n] = Point(, , , ); std::sort(p + , p + + n);
std::sort(h + , h + + n); m = std::unique(h + , h + + n) - h - ; for (int i = ; i <= n; ++i)
p[i].y = std::lower_bound(h + , h + + m, p[i].y) - h; for (int i = , j = ; i <= n; i = j)
{
while (j <= n && p[i].x == p[j].x)++j; for (int k = i; k < j; ++k)
{
MinMax l = lt.query(p[k].y - );
MinMax r = rt.query(m - p[k].y); if (l.min0.pos != p[k].z)
answer = std::max(answer, p[k].id - l.min0.val);
else
answer = std::max(answer, p[k].id - l.min1.val); if (l.max0.pos != p[k].z)
answer = std::max(answer, l.max0.val - p[k].id);
else
answer = std::max(answer, l.max1.val - p[k].id); if (r.min0.pos != p[k].z)
answer = std::max(answer, p[k].id - r.min0.val);
else
answer = std::max(answer, p[k].id - r.min1.val); if (r.max0.pos != p[k].z)
answer = std::max(answer, r.max0.val - p[k].id);
else
answer = std::max(answer, r.max1.val - p[k].id);
} for (int k = i; k < j; ++k)
{
lt.insert(p[k].y, MinMax(p[k].id, p[k].z));
rt.insert(m + - p[k].y, MinMax(p[k].id, p[k].z));
}
} printf("%d\n", answer);
}

BZOJ_4384.cpp

@Author: YouSiki

BZOJ 4384: [POI2015]Trzy wieże的更多相关文章

  1. [POI2015]Trzy wieże

    [POI2015]Trzy wieże 题目大意: 给定一个长度为\(n(n\le10^6)\)的仅包含'B'.'C'.'S'三种字符的字符串,请找到最长的一段连续子串,使得在这一段内出现过的所有字符 ...

  2. 【BZOJ4384】[POI2015]Trzy wieże 树状数组

    [BZOJ4384][POI2015]Trzy wieże Description 给定一个长度为n的仅包含'B'.'C'.'S'三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符 ...

  3. BZOJ4384 : [POI2015]Trzy wieże

    首先只有一种字符的情况可以通过双指针在$O(n)$的时间内处理完毕. 设$cnt[i][j]$表示前$i$个字符中$j$字符出现的次数,那么对于两个位置$j<i$: 如果 $cnt[i][0]- ...

  4. bzoj 4386: [POI2015]Wycieczki

    bzoj 4386: [POI2015]Wycieczki 这题什么素质,爆long long就算了,连int128都爆……最后还是用long double卡过的……而且可能是我本身自带大常数吧,T了 ...

  5. BZOJ 4385: [POI2015]Wilcze doły

    4385: [POI2015]Wilcze doły Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 648  Solved: 263[Submit][ ...

  6. Bzoj 3747: [POI2015]Kinoman 线段树

    3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 553  Solved: 222[Submit][Stat ...

  7. BZOJ 3747 POI2015 Kinoman 段树

    标题效果:有m点,每个点都有一个权值.现在我们有这个m为点的长度n该序列,寻求区间,它仅出现一次在正确的点区间内值和最大 想了很久,甚至神标题,奔说是水的问题--我醉了 枚举左点 对于每个请求留点右键 ...

  8. BZOJ 4380 [POI2015]Myjnie | DP

    链接 BZOJ 4380 题面 有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]. 有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个 ...

  9. BZOJ 3747 POI2015 Kinoman

    因为上午没有准备够题目,结果发现写完这道题没题可写了QAQ 又因为这道题范围是100w,我写了发线段树,以为要T,上午就花了一个小时拼命卡常数 结果下午一交居然过了QAQ 我们考虑枚举L,求最大R使得 ...

随机推荐

  1. wk_01

    Python 学习环境搭建 pyenv是个多版本python管理器,可以同时管理多个python版本共存,如pypy,miniconde等等.我们安装时其会将pyenv安装在当前用户家目录中的.pye ...

  2. 007商城项目:商品列表查询-需求分析,以及Spinmvc的访问知识

    我们之前已经整合了ssm框架并且调试已经好了,接下来我们实现商品列表的查询. 我们先进入到首页: 方法如下: 我们看到我们把所有的jsp页面都是放在: 这些页面都是放在WEB-IN下面的,也就是说这些 ...

  3. CSS IE6/7/8, Firefox, Safari, Chrome, Opera Hack使用简要归纳(转)

    网上有很多关于IE6/7/8, Firefox, Safari, Chrome, Opera CSS Hack的文章,但我觉得太过繁杂,要不给出一张看也看不懂的CSS Hack归纳表,要不就是给出一大 ...

  4. 返回标量CLR自定义函数

    昨天有学习了返回表自定义函数<CLR Table-Valued函数>http://www.cnblogs.com/insus/p/4378354.html.今天学习另一个,实现返回标量(S ...

  5. mvc route的注册,激活,调用流程

    mvc route的注册,激活,调用流程(三) net core mvc route的注册,激活,调用流程 mvc的入口是route,当前请求的url匹配到合适的route之后,mvc根据route所 ...

  6. Display HTML in WPF and CefSharp

    https://www.codeproject.com/articles/881315/display-html-in-wpf-and-cefsharp-tutorial-part Download ...

  7. 数据库 SQL语法一

    建立表语句 CREATE TABLE TABLENAME(COL_NAME1 TYPE,COL_NAME2 TYPE,......); 常用TYPE说明 INT 正数 CHAR(LENGTH) 定长字 ...

  8. 虾皮工作室QQ群列表

    各位博友: 本群不仅仅是提供好的资料,更重要是提供平台,提供解决问题的方法和思路.求人不如求己,掌握合理的方法和方式才是不断进步的根本.看我的文档,不单单是看内容,更应该从整理的方式和角度是深思,去想 ...

  9. LINQ的高级应用

    ---恢复内容开始--- 本文不想罗列linq的通俗使用方法.因为很多博文都已经写得很详细了. 此处直接贴出源码,如果有需要的朋友可以参考,希望更多的朋友能够补充更多的linq的高级应用. 源码如下: ...

  10. windows 下 redis for php 配置

    下载 redis,下载地址 https://github.com/dmajkic/redis/downloads,下载下来 zip 文件,解压,根据系统选择解压的文件夹(比如我的是 64bit). 我 ...