1 条题解

  • 0
    @ 2026-10-26 23:48:27

    思路与算法

    先顺序符号执行,将每个最终变量写成某个初始变量的正/反或常量。最终相等约束形成带奇偶关系的函数图,用带权并查集标记奇负环和连接U的分量,统计必须Unknown的人数。

    正确性说明

    符号执行严格复用当前右值,故保存的表达式等于完整程序的最终值。变量等式间边权为取反奇偶,同一分量若有奇负环则T/F都矛盾而U可行;连接U的分量也必须全U。其他分量的偶环或T/F常量可赋布尔值,无需U。每变量恰一个最终依赖,使一个弱分量不能同时含冲突的常量终点,因此这些必要条件也充分。

    复杂度

    O((n+m)α(n))时间、O(n)空间,含符号表达式、带权并查集与分量标记初始化;按大小合并。

    易错点

    赋值是顺序执行,不能把原操作直接当最终方程。逻辑非U仍U;排版的‐、−和半角-都作为取反操作串读取。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    struct DS {
        vector<int> p, s, x, bad;
        DS(int n) : p(n + 1), s(n + 1, 1), x(n + 1), bad(n + 1) {
            iota(p.begin(), p.end(), 0);
        }
        int find(int u) {
            if (p[u] == u)
                return u;
            int old = p[u];
            p[u] = find(old);
            x[u] ^= x[old];
            return p[u];
        }
        void join(int a, int b, int w) {
            int u = find(a), v = find(b);
            w ^= x[a] ^ x[b];
            if (u == v) {
                if (w)
                    bad[u] = 1;
                return;
            }
            if (s[u] > s[v])
                swap(u, v);
            p[u] = v;
            x[u] = w;
            s[v] += s[u];
            bad[v] |= bad[u];
        }
    };
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int c, T;
        cin >> c >> T;
        while (T--) {
            int n, m;
            cin >> n >> m;
            vector<int> e(n + 1);
            iota(e.begin(), e.end(), 0);
            for (int t = 0; t < m; t++) {
                string op;
                int i, j;
                cin >> op >> i;
                if (op == "T")
                    e[i] = n + 1;
                else if (op == "F")
                    e[i] = -(n + 1);
                else if (op == "U")
                    e[i] = n + 2;
                else {
                    cin >> j;
                    e[i] = op == "+" ? e[j] : -e[j];
                }
            }
            DS d(n);
            for (int i = 1; i <= n; i++)
                if (abs(e[i]) <= n)
                    d.join(i, abs(e[i]), e[i] < 0);
            for (int i = 1; i <= n; i++)
                if (abs(e[i]) == n + 2)
                    d.bad[d.find(i)] = 1;
            int ans = 0;
            for (int i = 1; i <= n; i++)
                ans += d.bad[d.find(i)];
            cout << ans << "\n";
        }
    }
    
    • 1

    信息

    ID
    1940
    时间
    1000ms
    内存
    512MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者