>
简要题意:给你一个由 B 和 W 构成字符串,每次操作可以删除一段由 个 B 和 个 W 构成的子串,求最多执行多少次操作。
结论:一段区间可以删空当且仅当存在一个非负整数 ,使得区间内 B 的个数等于 ,W 的个数等于 。
设 , 是前缀中 W 的个数, 是前缀中 B 的个数。
容易设计 的 DP。
考虑优化,将位置按照 分组,那么每次删的区间端点一定满足在同一组内,并且满足:
将 拆开,设 ,限制条件变为 。
显然这是一个三维偏序问题,我们使用 CDQ 分治,显然 是不重要的,我们排序处理一维的状态,另一维状态通过数据结构维护,设当前处理的区间是 大致流程如下:
预先处理初始状态的贡献。
若 ,说明该区间的所有 DP 值都是从前面继承来的。
递归求左区间的 DP 值,更新跨越中点的 DP 值,使用树状数组通过左区间的 DP 值更新右区间的 DP 值,然后继续递归求右区间的 DP 值。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
#define fir first
#define sec second
#define ep emplace
#define eb emplace_back
#define lowbit(x) ((x) & (-(x)))
inline int read() {
int x = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * f;
}
const int N = 500010, M = 1000000;
int n, xb, xw, len, cnt[N][2];
int f[N], tr[N << 1], stk[N];
char s[N];
struct Node {
int b, w, id, bid;
friend bool operator< (Node a, Node b) {
if (a.bid != b.bid) return a.bid < b.bid;
if (a.b != b.b) return a.b > b.b;
if (a.w != b.w) return a.w > b.w;
return a.id < b.id;
}
} a[N], tmp[N];
bool rec(Node a, Node b) { return a.id < b.id; }
void modify(int u, int v) { for (; u; u -= lowbit(u)) tr[u] = max(tr[u], v); }
int query(int u) {
int res = -0x3f3f3f3f;
for (; u <= M; u += lowbit(u)) res = max(res, tr[u]);
return res;
}
void clear(int u) { for (; u; u -= lowbit(u)) tr[u] = -0x3f3f3f3f; }
void cdq(int l, int r) {
if (r - l < len) {
for (int i = l + 1; i <= r; i ++ ) f[i] = max(f[i - 1], f[i]);
return;
}
int mid = (l + r) >> 1;
cdq(l, mid);
for (int i = l; i <= r; i ++ ) tmp[i] = a[i];
sort(a + l, a + r + 1);
int p = l;
for (int t = 0; t < len; t ++ ) {
int top = 0;
for (; p <= r && a[p].bid == t; p ++ ) {
int i = a[p].id;
if (i <= mid) modify(a[p].w, f[i] - i / len), stk[ ++ top] = p;
else f[i] = max(f[i], query(a[p].w) + i / len);
}
while (top) clear(a[stk[top]].w), top -- ;
}
f[mid + 1] = max(f[mid + 1], f[mid]);
for (int i = l; i <= r; i ++ ) a[i] = tmp[i];
cdq(mid + 1, r);
}
int main() {
n = read(), xb = read(), xw = read(), len = xb + xw;
scanf("%s", s + 1);
for (int i = 1; i <= n; i ++ ) {
cnt[i][0] = cnt[i - 1][0];
cnt[i][1] = cnt[i - 1][1];
if (s[i] == 'W') cnt[i][0] ++ ;
if (s[i] == 'B') cnt[i][1] ++ ;
}
for (int i = len; i <= n; i += len) {
int k = i / len;
int cw = cnt[i][0], cb = cnt[i][1];
if (cw > xw * k || cb > xb * k) continue;
f[i] = max(f[i], k);
}
for (int i = 1; i <= n; i ++ ) {
a[i].b = cnt[i][1] - (i / len) * xb + n;
a[i].w = cnt[i][0] - (i / len) * xw + n;
a[i].id = i, a[i].bid = i % len;
}
for (int i = 1; i <= M; i ++ ) tr[i] = -0x3f3f3f3f;
cdq(1, n);
printf("%d\n", f[n]);
return 0;
}