题目描述
给定一个序列,每次在其左端点或者右端点加入一个元素。
求这个序列的最长子段满足这个子段的 'W' 元素的个数等于 'D' 元素的个数。
正解
把 'W' 看成 1,把 'D' 看成 -1,若一个子段满足条件,则这个子段的和为 0。
记录前缀和,然后 要满足条件的话,
。
离线预处理出前缀和数组,用哈希表维护一个前缀和的出现位置就行。
时间复杂度 。
(貌似在线也能做
代码
#include <bits/stdc++.h>
#define N 2000005
using namespace std;
int n;
int arr[N + N], ltax[N + N], rtax[N + N], dir[N];
char s[N];
unordered_map<int, int> l, r;
int get(char ch = 0) {
while(ch != 'R' && ch != 'W' && ch != 'D') ch = getchar();
if(ch == 'R') return 0;
return ch == 'W' ? -1 : 1;
}
int main() {
int *f = arr + N, *psl = ltax + N, *psr = rtax + N;
int lp = 1, rp = 0, ans = 0;
int lsum = 0, rsum = 0;
scanf("%d", &n);
scanf("%s", s + 1);
int len = strlen(s + 1);
for(int i = 1; i <= len; ++i)
f[++rp] = get(s[i]);
for(int i = 1; i <= n; ++i) {
scanf("%d", &dir[i]);
if(dir[i] == 1) {
f[--lp] = get();
} else {
f[++rp] = get();
}
}
for(int i = lp; i <= rp; ++i) psr[i] = psr[i - 1] + f[i];
for(int i = rp; i >= lp; --i) psl[i] = psl[i + 1] + f[i];
lp = 1, rp = 0;
r[psr[rp]] = rp;
for(int i = 1; i <= len; ++i) {
++rp;
if(!r.count(psr[rp])) {
r[psr[rp]] = rp;
} else {
ans = max(ans, rp - r[psr[rp]]);
}
}
for(int i = 1; i <= len; ++i) l[psl[i]] = i;
l[psl[len + 1]] = len + 1;
printf("%d\n", ans);
for(int i = 1; i <= n; ++i) {
if(dir[i] == 1) {
--lp, r[psr[lp - 1]] = lp - 1;
if(!l.count(psl[lp])) {
l[psl[lp]] = lp;
} else {
ans = max(ans, l[psl[lp]] - lp);
}
} else {
++rp, l[psl[rp + 1]] = rp + 1;
if(!r.count(psr[rp])) {
r[psr[rp]] = rp;
} else {
ans = max(ans, rp - r[psr[rp]]);
}
}
printf("%d\n", ans);
}
return 0;
} 
京公网安备 11010502036488号