任何人都可以使用位掩码向我解释这种蛮力

问题描述

Educational Codeforces Round 105 的问题 A(评分为第 2 部分)。 Um_nik 用这种蛮力方法解决了这个问题,我并不完全理解。 我知道什么是位掩码,但我对 if ((mask >> (int)(s[i] - 'A')) & 1) 和 ok &= bal >= 0 感到困惑。 问题的链接是:https://codeforces.com/contest/1494/problem/A

    cin >> s;
    int n = (int)s.length();
    //cout << s << endl;
    for (int mask = 0; mask < (1 << 3); mask++) {
        int bal = 0;
        bool ok = true;
        for (int i = 0; i < n; i++) {
            if ((mask >> (int)(s[i] - 'A')) & 1)
                baL++;
            else
                bal--;
            ok &= bal >= 0;
        }
        ok &= bal == 0;
        if (ok) {
            printf("YES\n");
            return;
        }
    }
    printf("NO\n");

解决方法

我知道问题所在!

m的范围为0b000 ~ 0b111,第i位表示如果'A' + i是符号((如果不是,则是符号{{ 1}}).

例如,) 表示 m = 0b010。我需要使用 {'A': ')','B': '(','C': ')'} 来表示 m[CHAR],所以 (m >> (CHAR - 'A') & 1) ? '(' : ')'

我们知道m['B'] == '('是字符串s[i]中的第i个字符,所以s的意思是m >> (s[i] - 'A') & 1,如果第i个字符表示符号 m[s[i]]

例如(s = "ABBC"m = 0b010,所以i = 2,你就会知道s[i] == 'B'

最后,我们需要在开始时设置状态为m >> ('B' - 'A') & 1 == m['B'] == '(',然后如果满足0,则添加1,如果满足{,则减去( {1}}。如果状态总是 1,最后是 ),那么它有正确的答案,这就是我们需要打印 >= 0 并返回的原因。

,

算法背后的想法是尝试字母 A、B 和 C 的所有可能性。含义 A 可以是 '(' 或 ')',B 和 C 的含义相同。

因此我们有 8 种可能性,

A B C   in binary
( ( (   0 0 0
( ( )   0 0 1
( ) (   0 1 0
( ) )   0 1 1
) ( (   1 0 0 
) ( )   1 0 1
) ) (   1 1 0
) ) )   1 1 1

实际上,作者说 '(' is 0 and ')' is 1,或相反,以二进制形式涵盖 8 种可能性,即从 000 到 111。为什么“或相反 em>”?因为正如您在上面看到的,如果一个掩码为 001 提供 A:(、B:( 和 C:),另一个掩码 110 将呈现 A:)、B:) 和 C:( .

因此,掩码从 0 到 8-1 ((1 << 3)-1),或者,在二进制中,从 000 到 111。

例如,000 表示 A、B 和 C 都是左(或右)括号,而 110 在这种情况下是 ))(,表示 ABC(或 (())。

对于给定的掩码(外循环),内循环 for (int i = 0; i < n; i++) 遍历所有字符,并应用当前掩码。 (mask >> (int)(s[i] - 'A')) & 1 只是告诉,对于当前掩码,i 处的字母是 ( 还是 )

也就是说,(int)(s[i] - 'A') 为 A 提供 0,为 B 提供 1,为 C 提供 2。因此,A 获得位置 0 的位值(掩码的最右边位),B 是第 2nd 一位,C 是第 3rd(最左边)。

      C  B  A
mask b2 b1 b0

变量 bal 可能是 balance。每次遇到“开始” (() 字母时,bal 都会递增,然后递减 )

内循环中的 ok &= bal >= 0 确保在任何时候我们都没有比左括号更多的结束。因此,这会阻止 ABBA 被限定。

内循环之后的 ok &= bal == 0 确保我们有相同数量的左括号和右括号。

同样,为了避免混淆,掩码尝试了所有可能性,因此 ABAB 不符合 )()(,例如,掩码 001,但随后掩码到达010 给出符合条件的 ()()

注意:掩码很可能从 001 (1) 开始到 110 (6) 结束,因为 000 (0) 和 {{1 }} (7) 值永远不会起作用(将所有 A、B 和 C 分配给同一个括号不起作用)。