ABC277Ex - Constrained Sums 题解 2-SAT

题目链接:https://atcoder.jp/contests/abc277/tasks/abc277_h

用:

  • \(t(i,j,0)\) 表示 \(X_i \ge j\) 这个状态
  • \(t(i,j,1)\) 表示 \(X_i \lt j\) 这个状态

首先,对于任意 \(1 \le i \le n\)

  1. 能保证 \(X_i \ge 0\)
    • \(t(i,0,1) \to t(i,0,0)\)
  2. 能保证 \(X_i \lt m+1\)(即 \(X_i \le m\)
    • \(t(i,m+1,0) \to t(i,m+1,1)\)

对于任意 \(1 \le i \le n, 1 \le j \le m+1\)

  1. 如果 \(i \ge j\),则肯定满足 \(i \ge j-1\)
    • \(t(i,j,0) \to t(i,j-1,0)\)
  2. 如果 \(i \lt j-1\),则肯定满足 \(i \lt j\)
    • \(t(i,j-1,1) \to t(i,j,1)\)

对于每组 \(a, b, L, R\)

对于 \(X_a + X_b \ge L\)

对于 \(0 \le i \le m+1\)

  1. 如果 \(X_a \lt i\),则 \(X_b \ge L-i+1\)
    • \(j = \max(0, \min(m+1, L-i+1))\)
    • \(t(a, i, 1) \to (b, j, 0)\)
  2. 如果 \(X_b \lt i\),则 \(X_a \ge L-i+1\)
    • \(j = \max(0, \min(m+1, L-i+1))\)
    • \(t(b, i, 1) \to (a, j, 0)\)

对于 \(X_a + X_b \le R\)

对于 \(0 \le i \le m+1\)

  1. 如果 \(X_a \ge i\),则 \(X_b \lt R-i+1\)
    • \(j = \max(0, \min(m+1, R-i+1))\)
    • \(t(a, i, 0) \to t(b, j, 1)\)
  2. 如果 \(X_b \ge i\),则 \(X_a \lt R-i+1\)
    • \(j = \max(0, \min(m+1, R-i+1))\)
    • \(t(b, i, 0) \to t(a, j, 1)\)

另外就是拓扑排序,

因为 tarjan 的时候是 \(t(i,j,0)\)\(t(i,j,1)\) 先 tarjan,所以:

  • 如果 \(t(i,j,0)\) 可达 \(t(i,j,1)\),则 \(t(i,j,1)\) 所属的连通块编号小于 \((t(i,j,0))\)
  • 如果不可达,则 \(t(i,j,0)\) 所属的连通块编号小于 \((t(i,j,1))\)

也就是说,从小到大枚举 \(j\),找到最大的那个满足 \(X_i \ge j\)\(j\)

for (int i = 1; i <= n; i++) {
    for (int j = 0; j <= m+1; j++) {
        if (bl[ t[i][j][0] ] == bl[ t[i][j][1] ]) {
            puts("-1");
            return 0;
        }
        if (bl[ t[i][j][0] ] < bl[ t[i][j][1] ])
            ans[i] = j;
    }
}

或者,从大到小枚举 \(j\),找到最小的那个满足 \(X_i \lt j\)\(j-1\)

for (int i = 1; i <= n; i++) {
    for (int j = m+1; j >= 0; j--) {
        if (bl[ t[i][j][0] ] == bl[ t[i][j][1] ]) {
            puts("-1");
            return 0;
        }
        if (bl[ t[i][j][0] ] > bl[ t[i][j][1] ])
            ans[i] = j-1;
    }
}

(在完整代码的第 \(73 \sim 82\) 行)
这里,bl[x] 表示 \(x\) 所在连通块的编号。

链接.这份代码对我的帮助挺大

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2.2e4, maxm = maxn * 102 * 2;

int n, m, q, t[maxn][102][2], idx, ans[maxm];
vector<int> g[maxm];

int dfn[maxm], low[maxm], ts, bl[maxm], scc;
bool ins[maxm];
stack<int> stk;

void init() {
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= m+1; j++)
            for (int k = 0; k < 2; k++)
                t[i][j][k] = ++idx;
}

void add(int u, int v) {
    g[u].push_back(v);
}

void tarjan(int u) {
    dfn[u] = low[u] = ++ts;
    stk.push(u);
    ins[u] = true;
    for (auto v : g[u]) {
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (ins[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        scc++;
        int v;
        do {
            v = stk.top();
            stk.pop();
            ins[v] = false;
            bl[v] = scc;
        } while (u != v);
    }
}

int main() {
    scanf("%d%d%d", &n, &m, &q);
    init();
    for (int i = 1; i <= n; i++) {
        add(t[i][0][1], t[i][0][0]);
        add(t[i][m+1][0], t[i][m+1][1]);
        for (int j = 1; j <= m+1; j++) {
            add(t[i][j][0], t[i][j-1][0]);
            add(t[i][j-1][1], t[i][j][1]);
        }
    }
    while (q--) {
        int a, b, L, R;
        scanf("%d%d%d%d", &a, &b, &L, &R);
        for (int i = 0; i <= m+1; i++) {
            int j = max(0, min(m+1, L-i+1));
            add(t[a][i][1], t[b][j][0]);
            add(t[b][i][1], t[a][j][0]);
            j = max(0, min(m+1, R-i+1));
            add(t[a][i][0], t[b][j][1]);
            add(t[b][i][0], t[a][j][1]);
        }
    }
    for (int i = 1; i <= idx; i++)
        if (!dfn[i])
            tarjan(i);
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= m+1; j++) {
            if (bl[ t[i][j][0] ] == bl[ t[i][j][1] ]) {
                puts("-1");
                return 0;
            }
            if (bl[ t[i][j][0] ] < bl[ t[i][j][1] ])
                ans[i] = j;
        }
    }
    for (int i = 1; i <= n; i++)
        printf("%d ", ans[i]);
    return 0;
}
posted @ 2025-07-18 16:26  quanjun  阅读(14)  评论(0)    收藏  举报