BZOJ 4384: [POI2015]Trzy wieże

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+行就有多麻烦,至少不是很费脑子(才怪)。

代码

  1 #include <bits/stdc++.h>
  2 
  3 const int N = 1000005;
  4 const int inf = 1e9 + 7;
  5 
  6 int n, m;
  7 
  8 int h[N];
  9 
 10 char s[N];
 11 
 12 int sum[3];
 13 
 14 int answer;
 15 
 16 struct Point
 17 {
 18     int id, x, y, z;
 19     
 20     Point(void) {};
 21     Point(int i, int a, int b, int c)
 22     {
 23         id = i;
 24         x = a;
 25         y = b;
 26         z = c;
 27     }
 28     
 29     friend bool operator < (const Point &a, const Point &b)
 30     {
 31         return a.x < b.x;
 32     }
 33 }p[N];
 34 
 35 struct Pair
 36 {
 37     int val, pos;
 38     
 39     Pair(void) {};
 40     
 41     Pair(int a, int b)
 42     {
 43         val = a;
 44         pos = b;
 45     }
 46     
 47     friend bool operator ^ (const Pair &a, const Pair &b)
 48     {
 49         return a.pos != b.pos;
 50     }
 51     
 52     friend bool operator < (const Pair &a, const Pair &b)
 53     {
 54         return a.val < b.val;
 55     }
 56     
 57     friend bool operator > (const Pair &a, const Pair &b)
 58     {
 59         return a.val > b.val;
 60     }
 61 };
 62 
 63 struct MinMax
 64 {
 65     Pair min0;
 66     Pair min1;
 67     Pair max0;
 68     Pair max1;
 69     
 70     MinMax(void)
 71     {
 72         min0 = Pair(inf, -inf);
 73         min1 = Pair(inf, -inf);
 74         max0 = Pair(-inf, -inf);
 75         max1 = Pair(-inf, -inf);
 76     }
 77     
 78     MinMax(int val, int pos)
 79     {
 80         min0 = max0 = Pair(val, pos);
 81         min1 = Pair(inf, -inf);
 82         max1 = Pair(-inf, -inf);
 83     }
 84     
 85     friend MinMax operator + (const MinMax &a, const MinMax &b)
 86     {
 87         MinMax r;
 88         
 89         if (a.min0 < b.min0)
 90         {
 91             r.min0 = a.min0;
 92             if (a.min1 < b.min0)
 93                 r.min1 = a.min1;
 94             else if (a.min0 ^ b.min0)
 95                 r.min1 = b.min0;
 96             else if (a.min1 < b.min1)
 97                 r.min1 = a.min1;
 98             else
 99                 r.min1 = b.min1;
100         }
101         else
102         {
103             r.min0 = b.min0;
104             if (b.min1 < a.min0)
105                 r.min1 = b.min1;
106             else if (a.min0 ^ b.min0)
107                 r.min1 = a.min0;
108             else if (b.min1 < a.min1)
109                 r.min1 = b.min1;
110             else
111                 r.min1 = a.min1;
112         }
113         
114         
115         if (a.max0 > b.max0)
116         {
117             r.max0 = a.max0;
118             if (a.max1 > b.max0)
119                 r.max1 = a.max1;
120             else if (a.max0 ^ b.max0)
121                 r.max1 = b.max0;
122             else if (a.max1 > b.max1)
123                 r.max1 = a.max1;
124             else
125                 r.max1 = b.max1;
126         }
127         else
128         {
129             r.max0 = b.max0;
130             if (b.max1 > a.max0)
131                 r.max1 = b.max1;
132             else if (a.max0 ^ b.max0)
133                 r.max1 = a.max0;
134             else if (b.max1 > a.max1)
135                 r.max1 = b.max1;
136             else
137                 r.max1 = a.max1;
138         }
139         
140         return r;
141     }
142 };
143 
144 struct BIT
145 {
146     MinMax tree[N];
147     
148     int lowbit(int x)
149     {
150         return x & -x;
151     }
152     
153     MinMax query(int p)
154     {
155         MinMax r;
156         
157         while (p)
158         {
159             r = r + tree[p];
160             p -= lowbit(p);
161         }
162         
163         return r;
164     }
165     
166     void insert(int p, MinMax v)
167     {
168         while (p <= m)
169         {
170             tree[p] = tree[p] + v;
171             p += lowbit(p);
172         }
173     }
174 }lt, rt;
175 
176 signed main(void)
177 {
178     scanf("%d%s", &n, s + 1);
179     
180     for (int i = 1, j = 0; i <= n; ++i)
181     {
182         if (s[i] == s[i - 1])
183             answer = std::max(answer, ++j);
184         else
185             answer = std::max(answer, j = 1);
186     }
187     
188     for (int i = 1; i <= n; ++i)
189     {
190         switch (s[i])
191         {
192             case 'B': ++sum[0]; break;
193             case 'C': ++sum[1]; break;
194             case 'S': ++sum[2]; break;
195         }
196         
197         p[i] = Point(
198             i,
199             sum[0] - sum[1],
200             sum[1] - sum[2],
201             sum[2] - sum[0]
202         );
203         
204         h[i] = p[i].y;
205     }
206     
207     p[++n] = Point(0, 0, 0, 0);
208         
209     std::sort(p + 1, p + 1 + n);
210     std::sort(h + 1, h + 1 + n);
211     
212     m = std::unique(h + 1, h + 1 + n) - h - 1;
213     
214     for (int i = 1; i <= n; ++i)
215         p[i].y = std::lower_bound(h + 1, h + 1 + m, p[i].y) - h;
216         
217     for (int i = 1, j = 1; i <= n; i = j)
218     {
219         while (j <= n && p[i].x == p[j].x)++j;
220         
221         for (int k = i; k < j; ++k)
222         {
223             MinMax l = lt.query(p[k].y - 1);
224             MinMax r = rt.query(m - p[k].y);
225             
226             if (l.min0.pos != p[k].z)
227                 answer = std::max(answer, p[k].id - l.min0.val);
228             else
229                 answer = std::max(answer, p[k].id - l.min1.val);
230             
231             if (l.max0.pos != p[k].z)
232                 answer = std::max(answer, l.max0.val - p[k].id);
233             else
234                 answer = std::max(answer, l.max1.val - p[k].id);
235                 
236             if (r.min0.pos != p[k].z)
237                 answer = std::max(answer, p[k].id - r.min0.val);
238             else
239                 answer = std::max(answer, p[k].id - r.min1.val);
240             
241             if (r.max0.pos != p[k].z)
242                 answer = std::max(answer, r.max0.val - p[k].id);
243             else
244                 answer = std::max(answer, r.max1.val - p[k].id);
245         }
246         
247         for (int k = i; k < j; ++k)
248         {
249             lt.insert(p[k].y, MinMax(p[k].id, p[k].z));
250             rt.insert(m + 1 - p[k].y, MinMax(p[k].id, p[k].z));
251         }
252     }
253     
254     printf("%d
", answer);
255 }
BZOJ_4384.cpp

@Author: YouSiki

原文地址:https://www.cnblogs.com/yousiki/p/6061101.html