题解:CF2070E Game with Binary String
主要思路
很显然 Bob 每次就一定会尽可能取
令序列中
分类讨论:
- 若
c_0-3\times c_1 \ge 2 ,最终一定会剩下不少于两个的0 ,Alice 胜。 - 若
c_0 -3 \times c_1 = 0/1 ,最终剩下0/1 个0 ,Alice 无法操作,Bob 胜。 - 若
c_0 - 3 \times c_1 = -1 ,Alice 操作后只剩下一个1 ,Bob 无法操作,Alice 胜。 - 若
c_0 - 3 \times c_1 \le -2 ,最终会剩下若干个1 ,Bob 胜。
当然,每轮 Alice 能操作的前提是有相邻的两个
综上,只需要考虑满足
令
原式就变为
接下来就是动态开点板子了。
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 300010;
char s[N];
int rt = 1, idx = 1;
struct TREE {
int l, r, sum;
}tr[N * 20];
void insert(int &k, int l, int r, int p) {
if (!k) k = ++ idx;
if (l == r) {
tr[k].sum ++;
return;
}
int mid = l + r >> 1;
if (p <= mid) insert(tr[k].l, l, mid, p);
else insert(tr[k].r, mid + 1, r, p);
tr[k].sum = tr[tr[k].l].sum + tr[tr[k].r].sum;
}
int query(int k, int l, int r, int ql, int qr) {
if (!k) return 0;
if (l >= ql && r <= qr) return tr[k].sum;
int mid = l + r >> 1, re = 0;
if (ql <= mid) re = query(tr[k].l, l, mid, ql, qr);
if (qr > mid) re += query(tr[k].r, mid + 1, r, ql, qr);
return re;
}
signed main() {
int n;cin >> n;
cin >> s + 1;
int c0 = 0, c1 = 0, ans = 0;
insert(rt, -1e6, 1e6, 0);
for (int i = 1; i <= n; i ++ ) {
if (s[i] == '0') c0 ++;
else c1 ++;
int num = c0 - c1 * 3;
ans += query(1, -1e6, 1e6, -1e6, num - 2) + query(1, -1e6, 1e6, num + 1, num + 1);
insert(rt, -1e6, 1e6, num);
}
cout << ans;
return 0;
}