链接:
https://codeforces.com/problemset/problem/1535/C
t
组询问,每次给定一个仅包含字符1
或0
或?
字符串s
。定义一个子串是不稳定的当且仅当子串中任意相邻两数均不相同,如 101010…101010… 或 010101…010101…。其中?
可以变为1
或0
其中一种。请求出给定的s
中最多可以有的不稳定子串个数。
状态表示:
f
[
i
]
f[i]
f[i]:代表以
s
[
i
]
s[i]
s[i]结尾的满足题意子串的数目
状态转移:
f
[
i
]
=
f
[
i
−
1
]
+
1
f[i] = f[i - 1] +1
f[i]=f[i−1]+1
注意: f [ i − 1 ] f[i-1] f[i−1]转移到 f [ i ] f[i] f[i]的前提是 s [ i − 1 ] s[i-1] s[i−1]与 s [ i ] s[i] s[i]可以组成满足题意的字符串,即 s [ i ] ! = s [ i − 1 ] s[i]!=s[i-1] s[i]!=s[i−1]
因为前面可能有?
字符, s [ i − 1 ] s[i-1] s[i−1]不一定是数字,所以中途要记录一个下标pre
代表距离i
的最近的非?
字符下标
pre决定了 [ p r e , i ] [pre,i] [pre,i]之间字符串的01状态,因为 s [ p r e ] s[pre] s[pre]已经确定
对转移进一步解释:
- s [ i ] = ′ ? ′ s[i]='?' s[i]=′?′,该字符可以与前面的一个字符形成目标子串
-
s
[
i
]
s[i]
s[i]为数字,需要找距离
i
最近的数字 s [ p r e ] s[pre] s[pre]进行判断,看 s [ p r e ] s[pre] s[pre]和 s [ i ] s[i] s[i]能否组成目标子串- 可以正常转移的条件:
- i − p r e i-pre i−pre为偶数且 s [ i ] = = s [ p r e ] s[i]==s[pre] s[i]==s[pre]
- i − p r e i-pre i−pre为奇数且 s [ i ] ! = s [ p r e ] s[i]!=s[pre] s[i]!=s[pre]
- p r e = 0 pre=0 pre=0,代表还没有遇到数字
- 可以正常转移的条件:
最后把以每一个字符结尾的结果加起来就可以了
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
{
string s;
cin >> s;
int n = s.size();
s = " " + s;
vector<ll> f(n + 1, 0);
int pre = 0;
for(int i = 1; i <= n; i++)
{
if(s[i] == '?') f[i] = f[i - 1] + 1;
else
{
int x = s[pre] - '0', y = s[i] - '0';
if(pre == 0 || (i - pre) % 2 == 0 and x == y || (i - pre) & 1 and x != y)
f[i] = f[i - 1] + 1;
else
f[i] = i - pre;
pre = i;
}
}
ll res = 0;
for(int i = 1; i <= n; i++)
res += f[i];
cout << res << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
// t = 1;
while(t--)
solve();
return 0;
}