题解:[ARC188C] Honest or Liar or Confused

乍一看以为是 3-SAT 不可做,动动脑子发现是 2-SAT(

鉴于本题解书写时洛谷题面暂无中文翻译,为避免可能的歧义或困惑,先对本题解中的译法进行约定:

  • 英文题面中“honest villager”或日文题面中“正直者”译为“诚实村民”。
  • 英文题面中“liar”或日文题面中“嘘つき”译为“撒谎村民”。
  • 英文题面中“confused”或日文题面中“混乱している”译为“糊涂的”。
  • 英文题面中“not confused”或日文题面中“混乱していない”译为“清醒的”。
  • 英文题面中“testimony”或日文题面中“証言”译为“证言”。

Pi 表示第 i 位村民是否是撒谎村民,Qi 表示第 i 位村民是否是糊涂的。根据题意列出证言的真值表:

A 身份 PA A 状态 QA B 身份 PB C 结果 C
诚实村民 0 清醒的 0 诚实村民 0 诚实村民 0
诚实村民 0 清醒的 0 撒谎村民 1 撒谎村民 1
诚实村民 0 糊涂的 1 诚实村民 0 撒谎村民 1
诚实村民 0 糊涂的 1 撒谎村民 1 诚实村民 0
撒谎村民 1 清醒的 0 诚实村民 0 撒谎村民 1
撒谎村民 1 清醒的 0 撒谎村民 1 诚实村民 0
撒谎村民 1 糊涂的 1 诚实村民 0 诚实村民 0
撒谎村民 1 糊涂的 1 撒谎村民 1 撒谎村民 1

容易观察到证言 (A,B,C) 实际上限制了 PAQAPB=C

注意到,一位村民是否是撒谎村民和她是否清醒是无关的,并且上式中 PAQA 总是绑定在一起,因此不难想到设 Ri=PiQi。证言 (A,B,C) 的限制转化为 RAPB=C,是经典的 2-XOR-SAT 问题。使用扩展域并查集求解出 PiRi 的一组解(或判定无解),再根据 Qi=PiRi 求得并输出 Qi 即可。

题目要求构造出一组解(而非判定是否有解),构造的过程比较容易想不清楚写错,赛时直接爽吃五发罚时。

核心代码:

//By: OIer rui_er
#define rep(x, y, z) for(int x = (y); x <= (z); ++x)
#define per(x, y, z) for(int x = (y); x >= (z); --x)

const int N = 8e5 + 5;

int n, m, ans[N];

struct Dsu {
    int fa[N];
    void init(int x) {rep(i, 1, x) fa[i] = i;}
    int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
    bool same(int x, int y) {return find(x) == find(y);}
    bool merge(int x, int y) {
        if(same(x, y)) return false;
        x = find(x); y = find(y);
        fa[x] = y;
        return true;
    }
}dsu;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> m;
    dsu.init(4 * n);
    rep(i, 1, m) {
        int u, v, w;
        cin >> u >> v >> w;
        if(w == 0) {
            dsu.merge(u + 2 * n, v);
            dsu.merge(u + 2 * n + n, v + n);
        }
        else {
            dsu.merge(u + 2 * n, v + n);
            dsu.merge(u + 2 * n + n, v);
        }
    }
    rep(i, 1, n) {
        if(dsu.same(i, i + n)) {
            cout << "-1" << endl;
            return 0;
        }
        if(dsu.same(i + 2 * n, i + 2 * n + n)) {
            cout << "-1" << endl;
            return 0;
        }
    }
    // rep(i, 1, n) cout << dsu.find(i) << " " << dsu.find(i + n) << " " << dsu.find(i + 2 * n) << " " << dsu.find(i + 3 * n) << endl;
    rep(i, 1, n) {
        if(dsu.same(i, i + 2 * n)) cout << 0;
        else if(dsu.same(i, i + 2 * n + n)) cout << 1;
        else {
            dsu.merge(i + 2 * n, i);
            dsu.merge(i + 2 * n + n, i + n);
            cout << 0;
        }
    }
    cout << endl;
    return 0;
}
posted @   rui_er  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示