给定一个仅包含0,1,?的字符串,问能有多少个子串符合010101或者101010这种情况。
一开始的思路是枚举匹配01,然后?加到每个能匹配的子串前,过了样例然后WA2了。
尝试去看题解,发先不是很好理解。
去看了看榜单上厉害的大佬是怎么写的,揣摩了一会,似懂似不懂的抄了一遍代码,过掉了。
然后又思索了一会,发先好像又有点思路,但就是不知道是啥思路。
去看了看tiger2005的题解,恍然大悟。解法如下:
将子串跟两种合法形式的串匹配,A(010101),B(101010),然后就将字符串分为三类,A,B,?,问题就变成了求解连续A,B的子串长度。
然后将A类,B类下标塞进一个vector a[3]中的0,1,还有一个将A,B下标同时塞进a[2].
然后统计\((a[i][j + 1] - a[i][j]) * (a[i][j + 1] - a[i][j] - 1) / 2\),放进res[3]中。
结果就是\(res[1] + res[0] - res[2]\);
解释:res[0] : 存放的其实是所有满足B类条件的子串长度,res[1] : 其实就是所有满足A类条件的子串长度。res[2] : 是所有连续?的重复次数。
所学习的网站:
tiger2005讲解
大佬Code
char s[N];
void solve() {
cin >> (s );
int len = strlen(s );
vector<vector<int> > a(3);
for(int i = 0; i < 3;++i) a[i].push_back(-1);
for(int i = 0;i < len;++i) {
if(s[i] == ‘?‘) continue;
int p = (s[i] - ‘0‘ + i) % 2;
a[p].push_back(i);
a[2].push_back(i);
}
for(int i = 0; i < 3;++i) a[i].push_back(len);
vector<ll> res(3,0);
for(int i = 0; i < 3;++i) {
for(int j = 0;j < a[i].size() - 1;++j) {
ll tmp = a[i][j + 1] - a[i][j];
res[i] += tmp * (tmp - 1) / 2;
}
}
cout << res[1] + res[0] - res[2] << endl;
}
原文:https://www.cnblogs.com/Wise4/p/14865607.html