CF 1535C Unstable String

题目描述

http://codeforces.com/contest/1535/problem/C

简要题意:给定一个含有 $0,1,?$ 的字符串,$?$ 可以变成 $0$ 或者 $1$,求有多少子串满足存在一种将 $?$ 替换成 $0$ 或者 $1$ 的方案,使得这个子串不存在有任何两个相邻位置的字符相同

$n\le 2\times 10^5$

Solution

首先是一个非常弱智的想法,我们令 $f[0/1]$ 表示以 $0$ 或者以 $1$ 结尾的合法区间的个数,但是这样 $?$ 是不能转移的,然后就自闭了

那么我们换一个方向来考虑,首先对于任意一个合法子串 $[l,r]$,它的子区间都是合法的,那么我们可以对于每个点记录以它结尾的最长合法区间

我们同样以 $f[0/1]$ 来表示以 $0$ 或者以 $1$ 结尾的最长合法区间的长度,然后这样 $?$ 就能转移了,而在计算答案时我们只需要加上 $max\lbrace f[0],f[1]\rbrace$ 即可

这道题让我觉得自己像一个弱智

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <algorithm>
#include <cstring>
#define maxn 200010
#define ll long long
using namespace std;

int n;

ll f[2];

char s[maxn];

void work() {
cin >> s + 1; n = strlen(s + 1); f[0] = f[1] = 0; ll ans = 0;
for (int i = 1; i <= n; ++i) {
if (s[i] == '0') f[0] = f[1] + 1, f[1] = 0;
if (s[i] == '1') f[1] = f[0] + 1, f[0] = 0;
if (s[i] == '?') {
int x = f[0], y = f[1];
f[0] = y + 1; f[1] = x + 1;
}
ans += max(f[0], f[1]);
} cout << ans << "\n";
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

int T; cin >> T;
while (T--) work();
return 0;
}