zoukankan      html  css  js  c++  java
  • ZOJ-4028 LIS (差分约束)

    题目链接:ZOJ-4028 LIS

    题意

    有一个长度为 (n (1le n le 10^5)) 的序列 (a),对于所有的 (iin [1,n]) ,已知 (f_i, l_i, r_i) ,代表序列 (a) 中末尾元素为 (a_i) 的最长上升子序列长度为 (f_i) ,且 (l_i le a_i le r_i) ,求序列 (a)


    思路

    找出 (a_i) 的所有约束条件:

    1. (i')(i) 前面满足 (f_{i'}=f_i) 的离 (i) 最近的位置,(a_i) 的值需要满足 (a_i le a_{i'}) ;
    2. (i'')(i) 前面满足 (f_{i''}+1=f_i) 的离 (i) 最近的位置,(a_i) 的值需要满足 (a_i>a_{i''}) ;
    3. (l_ile a_ile r_i)

    知道了每个 (a_i) 的约束条件,可以用差分约束求解(用 (e(u,v,w)) 代表从 (u)(v) 权值为 (w) 的有向边):

    1. (a_ile a_{i'}) 可变形为 (a_ile a_{i'}+0) ,连边 (e(i',i,0)) ;
    2. (a_i>a_{i''}) 可变形为 (a_{i''}le a_i-1) ,连边 (e(i,i'',-1)) ;
    3. 新增一个源点 (s),令 (a_s=0)(l_ile a_ile r_i) 可变形为 (a_sle a_i-l_i, a_ile a_s+r_i) ,连边 (e(i,s,-l_i), e(s,i,r_i))

    建完图跑差分约束即可。


    代码实现

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using std::queue;
    typedef long long LL;
    const int maxn = 100010;
    int head[maxn], tot;
    LL dist[maxn];
    int f[maxn], last[maxn];
    bool inq[maxn];
    struct Edge{
        int to, nex, val;
    } edge[maxn<<2];
    void add_edge(int u, int v, int w) {
        edge[++tot].nex = head[u];
        edge[tot].to = v;
        edge[tot].val = w;
        head[u] = tot;
    }
    void bfs_spfa(int s, int n) {
        memset(inq, 0, sizeof(bool) * (n+5));
        memset(dist, 0x3f, sizeof(LL) * (n+5));
        queue<int> que;
        que.push(s);
        inq[s] = true;
        dist[s] = 0;
        while (!que.empty()) {
            int u = que.front();
            que.pop();
            inq[u] = false;
            for (int i = head[u]; i; i = edge[i].nex) {
                int v = edge[i].to;
                if (dist[v] > dist[u] + edge[i].val) {
                    dist[v] = dist[u] + edge[i].val;
                    if (!inq[v]) {
                        inq[v] = true;
                        que.push(v);
                    }
                }
            }
        }
        for (int i = 1; i <= n; i++) printf("%lld%c", dist[i], " 
    "[i==n]);
    }
    
    int main() {
        int T, n;
        scanf("%d", &T);
        while (T--) {
            scanf("%d", &n);
            memset(last, 0, sizeof(int) * (n+5));
            memset(head, 0, sizeof(int) * (n+5));
            tot = 0;
            for (int i = 1; i <= n; i++) {
                scanf("%d", &f[i]);
                if (last[f[i]]) add_edge(last[f[i]], i, 0);
                if (f[i] > 1) add_edge(i, last[f[i]-1], -1);
                last[f[i]] = i;
            }
            for (int i = 1, l, r; i <= n; i++) {
                scanf("%d %d", &l, &r);
                add_edge(0, i, r);
                add_edge(i, 0, -l);
            }
            bfs_spfa(0, n);
        }
        return 0;
    }
    
  • 相关阅读:
    牛客网 二叉树的镜像 JAVA
    牛客网 反转链表 JAVA
    牛客网 调整数组顺序使奇数位于偶数前面 JAVA
    Integer to Roman LeetCode Java
    Valid Number leetcode java
    Longest Common Prefix
    Wildcard Matching leetcode java
    Regular Expression Matching
    Longest Palindromic Substring
    Add Binary LeetCode Java
  • 原文地址:https://www.cnblogs.com/kangkang-/p/13512581.html
Copyright © 2011-2022 走看看