题目描述
给定一个序列,每次在其左端点或者右端点加入一个元素。
求这个序列的最长子段满足这个子段的 '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; }