CF 1535C-Unstable String

image

题意

给定一个仅包含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

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;
}
posted @ 2021-06-09 09:43  Wise_4  阅读(91)  评论(0编辑  收藏  举报