本文已参与「新人创作礼」活动,一起开启掘金创作之路。
链接:
codeforces.com/problemset/…
t组询问,每次给定一个仅包含字符1或0或?字符串s。定义一个子串是不稳定的当且仅当子串中任意相邻两数均不相同,如 101010…101010… 或 010101…010101…。其中?可以变为1或0其中一种。请求出给定的s中最多可以有的不稳定子串个数。
状态表示:
:代表以结尾的满足题意子串的数目
状态转移:
注意:转移到的前提是与可以组成满足题意的字符串,即
因为前面可能有?字符,不一定是数字,所以中途要记录一个下标pre代表距离i的最近的非?字符下标
pre决定了之间字符串的01状态,因为已经确定
对转移进一步解释:
-
,该字符可以与前面的一个字符形成目标子串
-
为数字,需要找距离
i最近的数字进行判断,看和能否组成目标子串-
可以正常转移的条件:
-
为偶数且
-
为奇数且
-
,代表还没有遇到数字
-
-
最后把以每一个字符结尾的结果加起来就可以了
#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;
}