cf1697 F. Too Many Constraints

题意:

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

  • 1 i x 表示 aix
  • 2 i j x 表示 ai+ajx
  • 3 i j x 表示 ai+ajx

2n2e4,0m2e4,2k10

思路:

k 很小。开 nk 个点,pik+x=1 表示 aix,那就转化成 2-sat 问题

  • (初始限制)

ai1

aikai<k+1!(aik+1)

aix+1aix

aixai+1x

  • aix

ai<xaix+1!(aix)(aix+1)

  • ai+ajx

yaiyajxyaj<xy+1!(ajxy+1)

  • ai+ajx

y!(aiy+1)ai<y+1aiyajxy

为了写码方便,把值域写成 [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;
}
posted @   Bellala  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示