其他分享
首页 > 其他分享> > cf1697 F. Too Many Constraints

cf1697 F. Too Many Constraints

作者:互联网

题意:

构造长度为 \(n\)、单调不降、值域为 \([1,k]\) 的数组。要求满足 \(m\) 个条件,条件有三种类型:

\(2\le n\le 2e4, 0\le m\le 2e4, 2\le k\le 10\)

思路:

\(k\) 很小。开 \(nk\) 个点,\(p_{ik+x}=1\) 表示 \(a_i\ge x\),那就转化成 2-sat 问题

\(a_i\ge 1\)

\(a_i\le k\iff a_i<k+1\iff !(a_i\ge k+1)\)

\(a_i\ge x+1\implies a_i\ge x\)

\(a_i\ge x\implies a_{i+1}\ge x\)

\(\iff a_i<x\or a_i\ge x+1\iff !(a_i\ge x)\or (a_i\ge x+1)\)

\(\forall y\),\(a_i\ge y \implies a_j\le x-y \iff a_j<x-y+1\iff !(a_j\ge x-y+1)\)

\(\forall y\),\(!(a_i\ge y+1)\iff a_i<y+1\iff a_i\le y\implies a_j\ge x-y\)

为了写码方便,把值域写成 \([0,k+1]\)。

struct TwoSat {
    int n;
    vector<vector<int>> G;
    vector<bool> ans;
    TwoSat(int n) : n(n), G(2*n), ans(n) {}
    void Or(int u, bool f, int v, bool g) { //至少一个为真
        G[2*u+!f].pb(2*v+g), G[2*v+!g].pb(2*u+f);
    }
    void Implies(int u, bool f, int v, bool g) { //u=f → v=g
        Or(u, !f, v, g);
    }
    void Xor(int u, bool f, int v, bool g) { //恰一个为真
        Or(u, f, v, g), Or(u, !f, v, !g);
    }
    void Same(int u, bool f, int v, bool g) { //同时为真/假
        Xor(u, !f, v, g);
    }
    void Must(int u, bool f) { //u=f
        Or(u, f, u, f);
    }
    bool work() {
        vector<int> id(2*n,-1), dfn(2*n,-1), low(2*n,-1), stk;
        int now = 0, cnt = 0;
        function<void(int)> tarjan = [&](int u) {
            stk.pb(u);
            dfn[u] = low[u] = now++;
            for(auto v : G[u]) {
                if(dfn[v] == -1) {
                    tarjan(v);
                    low[u] = min(low[u], low[v]);
                } else if(id[v] == -1) low[u] = min(low[u], dfn[v]);
            }
            if(dfn[u] == low[u]) {
                int v; do {
                    v = stk.back();
                    stk.pop_back();
                    id[v] = cnt;
                } while (v != u);
                ++cnt;
            }
        };
        for(int i = 0; i < 2*n; i++)
            if(dfn[i] == -1) tarjan(i);
        for(int i = 0; i < n; i++) {
            if(id[2*i] == id[2*i+1]) return false;
            ans[i] = id[2*i] > id[2*i+1];
        }
        return true;
    }
};

void sol() {
    int n, m, k; cin >> n >> m >> k;

    int K = k + 2;
    TwoSat ts(n*K); //未拆点的点数

    #define p(i,x) (i)*K+x //a[i]取x的点号

    for(int i = 0; i < n; i++) {
        for(int x = 1; x <= k+1; x++)
            ts.Implies(p(i,x), true, p(i,x-1), true);
        ts.Must(p(i,1), true);
        ts.Must(p(i,k+1), false);
    }
    
    for(int i = 1; i < n; i++)
        for(int x = 0; x <= k+1; x++)
            ts.Implies(p(i-1,x), true, p(i,x), true);

    while(m--) {
        int t, i, j, x; cin >> t;
        if(t == 1) { //a[i]!=x
            cin >> i >> x; i--;
            ts.Or(p(i,x), false, p(i,x+1), true);
        }
        if(t == 2) { //a[i]+a[j]<=x
            cin >> i >> j >> x; i--, j--;
            for(int y = max(0,x-k); y <= min(k+1,x+1); y++)
                ts.Implies(p(i,y), true, p(j,x-y+1), false),
                ts.Implies(p(j,y), true, p(i,x-y+1), false);
        }
        if(t == 3) { //a[i]+a[j]>=x
            cin >> i >> j >> x; i--, j--;
            for(int y = max(0,x-k-1); y <= min(k,x); y++)
                ts.Implies(p(i,y+1), false, p(j,x-y), true),
                ts.Implies(p(j,y+1), false, p(i,x-y), true);
        }
    }

    if(ts.work()) {
        for(int i = 0, las = 0; i < n; i++) {
            for(int x = 1; x <= k; x++)
                if(ts.ans[p(i,x)]) las = x; //最后一个满足a[i]>=x的x
            cout << las << " \n"[i == n-1];
        }
    }
    else cout << -1 << endl;
}

标签:le,int,Many,cf1697,ge,bool,Too,id,low
来源: https://www.cnblogs.com/wushansinger/p/16480963.html