• POJ1201 Intervals 差分约束(贪心也可)


    题面

    给定 n 个区间 [ai,bi]和 n 个整数 ci。

    你需要构造一个整数集合 Z,使得∀i∈[1,n],Z 中满足ai≤x≤bi的整数 x 不少于 ci 个。

    求这样的整数集合 Z 最少包含多少个数。

    输入格式

    第一行包含整数 n。

    接下来n行,每行包含三个整数ai,bi,ci。

    输出格式

    输出一个整数表示结果。

    数据范围

    1≤n≤50000,
    0≤ai,bi≤50000,
    1≤ci≤bi−ai+1
    

    输入样例:

    5
    3 7 3
    8 10 3
    6 8 1
    1 3 1
    10 11 1
    

    输出样例:

    6
    

    题解

    差分约束

    一堆不等式, 明显是差分约束

    设 s[i], 表示 0~i 区间选择了 s[i] 个数

    则 s[b] - s[a - 1] >= c

    只是这样的话, 不能将 -1(a >= 0, a - 1 >= -1)~5e4 每个节点连接起来

    我们发现 s[i] - s[i - 1] >= 0, s[i - 1] - s[i] >= -1

    这样就将所有节点全部连接起来, 由于解的存在, 无负环,

    对于差分约束, 要么把所有点扔进队列, 要么选择一个初始节点

    对于这道题要么把, 0~50000全扔进去, 要么从 -1, s[-1] ≡ 0

    由于越界, 我们将 -1 由 5e4 + 1代替, 或者整体将区间右移, 变为 0~50001

    const int N = 5e4 + 5;
    const double eps = 1e-6;
    
    int n, m, _, k;
    int h[N], ne[N << 2], to[N << 2], co[N << 2], tot;
    int a[N], b[N], c[N], dis[N];
    bool v[N];
    
    void add(int u, int v, int c) {
        ne[++tot] = h[u]; co[h[u] = tot] = c; to[tot] = v;
    }
    
    void spfa(int s) {
        queue<int> q;
        memset(dis, -1, sizeof dis);
        q.push(s); dis[s] = 0;
        while (!q.empty()) {
            int x = q.front(); q.pop(); v[x] = 0;
            for (int i = h[x]; i; i = ne[i]) {
                int y = to[i];
                if (dis[y] >= dis[x] + co[i]) continue;
                dis[y] = dis[x] + co[i];
                if (!v[y]) q.push(y), v[y] = 1;
            }
        }
    }
    
    int main() {
        sc(n);
        rep(i, 1, 5e4) add(i - 1, i, 0), add(i, i - 1, -1);
        add(5e4 + 1, 0, 0); add(0, 5e4 + 1, -1);
        rep(i, 1, n) {
            sc(a[i]), sc(b[i]), sc(c[i]); --a[i];
            if (a[i] == -1) a[i] = 5e4 + 1;
            add(a[i], b[i], c[i]);
        }
        spfa(5e4 + 1);
        pr(dis[50000]);
        return 0;
    }
    

    贪心

    将b按照升序排列, 尽量将数字靠近 b 放置, 加上树状数组,并查集优化, 即可

    const int N = 5e4 + 5;
    const double eps = 1e-6;
    
    int n, m, _, k;
    int c[N], f[N];
    pair<PII, int> p[N];
    
    void add(int x, int k) {
        for (; x <= 5e4; x += -x & x) c[x] += k;
    }
    
    int ask(int x) {
        int ans = 0;
        for (; x; x -= -x & x) ans += c[x];
        return ans;
    }
    
    int find(int x) {
        if (x == f[x]) return x;
        return f[x] = find(f[x]);
    }
    
    int main() {
        sc(n);
        rep(i, 1, n) sc(p[i].fi.se), sc(p[i].fi.fi), sc(p[i].se);
        rep(i, 1, 5e4 + 1) f[i] = i;
        sort(p + 1, p + 1 + n);
        rep(i, 1, n) {
            int x = p[i].fi.se + 1, y = p[i].fi.fi + 1, cnt = p[i].se;
            cnt -= ask(y) - ask(x - 1);
            if (cnt <= 0) continue;
            for (int j = find(y); cnt; j = f[j])
                --cnt, add(j, 1), f[j] = find(j - 1), ++m;
        }
        pr(m);
        return 0;
    }
    
  • 相关阅读:
    Mysql知识总结
    Unity3D UGUI 自动调节大小
    关于 Rijndael 加密
    配置java环境
    二叉查找树
    序列化和反序列化
    关于文件保存/关闭时报错:文件正由另一进程使用,因此该进程无法访问此文件。
    关于Unity中NGUI图片精灵响应鼠标的方法
    用人类的话来描述 里氏转换
    C#中string的相关方法
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/13616148.html
Copyright © 2020-2023  润新知