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
分析
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\n", answer); 255 }
BZOJ_4384.cpp
@Author: YouSiki