bzoj3716/4251 [PA2014]Muzeum

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3716

http://www.lydsy.com/JudgeOnline/problem.php?id=4251

【题解】

非常妙的网络流转化

首先可以把警卫和宝藏看成最大权闭合子图,用最小割的那种建模方法,即一开始加进来所有宝藏的价值

然后S连宝藏,警卫连T,有覆盖关系的连inf

那么就是一个最小割,复杂度是$O(maxflow(n+m, nm)$,显然承受不了。

由于最小割和最大流等价,所以转化最大流考虑。

问题变为

那么按x从大到小排序,每次2种操作:加入一个物品;有一个警卫可以喷水给所有y小于它物品。

显然按照y从大到小喷最优,因为小的限制条件小。

用个set维护即可,注意set的时候lower_bound只能s.lower_bound(...),不能lower_bound(s.begin(), s.end(), ..)!!!

# include <set>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N = 2e5 + 10;
const int mod = 1e9+7;
const ll inf = 5e18;

inline int getint() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == ‘-‘) f = 0;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x<<3) + (x<<1) + ch - ‘0‘;
        ch = getchar();
    }
    return f ? x : -x;
}

int n, m, W, H;
struct pa {
    ll x, y; int v;
    pa () {}
    pa (ll x, ll y, int v) : x(x), y(y), v(v) {}
    inline friend bool operator < (pa a, pa b) {
        return a.y < b.y || (a.y == b.y && a.x < b.x);
    }
}a[N], b[N];

struct option {
    ll x, y; int v, op;
    option() {}
    option(int op, ll x, ll y, int v) : op(op), x(x), y(y), v(v) {}
    inline friend bool operator < (option a, option b) {
        return a.x < b.x || (a.x == b.x && a.op > b.op);
    }
}p[N + N]; 

set<pa> s;
set<pa>::iterator it;

int main() {
    ll ans = 0;
    cin >> n >> m >> W >> H;
    for (int i=1; i<=n; ++i) {
        a[i].x = 1ll * H * getint(), a[i].y = 1ll * W * getint(), a[i].v = getint();
        p[i] = option(1, a[i].x - a[i].y, a[i].x + a[i].y, a[i].v); ans += a[i].v;
    }
    for (int i=1; i<=m; ++i) {
        b[i].x = 1ll * H * getint(), b[i].y = 1ll * W * getint(), b[i].v = getint();
        p[n + i] = option(2, b[i].x - b[i].y, b[i].x + b[i].y, b[i].v);
    }

    // maxflow
    int pn = n + m;
    sort(p+1, p+pn+1); s.clear(); 

    for (int i=pn; i; --i) {
        if(p[i].op == 1) s.insert(pa(p[i].x, p[i].y, p[i].v));
        else {
            int cv = p[i].v;
            pa r = pa(inf, p[i].y, cv), t;
            while(cv && s.size()) {
                it = s.upper_bound(r);
                if(it == s.begin()) break;
                --it; t = *it; s.erase(it);
                int tmp = min(t.v, cv);
                cv -= tmp, t.v -= tmp; ans -= tmp;
                if(t.v > 0) s.insert(t);
            }
        }
    }

    cout << ans;

    return 0;
}

时间: 2024-10-12 03:08:41

bzoj3716/4251 [PA2014]Muzeum的相关文章

[PA2014]Muzeum

[PA2014]Muzeum 题目大意: 有\(n\)件展品和\(m\)个警卫,每件展品有一个坐标\((x_i,y_i)\)和价值\(v_i\),每个警卫的坐标为\((x_i,y_i)\).每个警卫面朝\(y\)轴负方向,左右视角都为\(\theta\),警卫视线范围内的展品不能偷.你可以收买一些警卫,使其放弃安保工作,收买第\(i\)个警卫的价格为\(v_i\).你需要收买一些警卫并偷走一些展品,求盗取的总价值\(-\)收买的支出的最大值. 思路: \(\tan(\theta)=\frac w

bzoj 3716: [PA2014]Muzeum

Description 吉丽的漫展有n件手办和m名警卫.建立平面直角坐标系,每个手办和警卫都可以看做一个点.警卫们的目光都朝着y轴负方向,且都有相同大小的视角.警卫可以看见自己视角内(包括边界上的点)的所有手办,不用考虑视线的遮挡. 你打算抢劫吉丽的漫展,但不可被警卫发现.为了实施这次抢劫计划,你可以事先贿赂某些警卫,让他们闭上眼睛.只要某件手办不在任何睁着眼睛的警卫的视野内,你就可以偷走它.你知道每件手办的价格,以及每位警卫需要接受多少钱的贿赂.你想知道自己的最大收益是多少. Solution

我与PA有个约定

bzoj3546:[ONTAK2010]Life of the Partybzoj3548:[ONTAK2010]Partybzoj3709:[PA2014]Bohaterbzoj3710:[PA2014]Ciagibzoj3711:[PA2014]Druzyny ****bzoj3713:[PA2014]Iloczynbzoj3714:[PA2014]Kuglarzbzoj3715:[PA2014]Lustrabzoj3716:[PA2014]Muzeumbzoj3717:[PA2014]Pa

省选之前的未完成的计划(截至到省选)

PLAN OF THE COMING HEOI good problems:-bzoj4823:[Cqoi2017]老C的方块 [*]-bzoj3171:[Tjoi2013]循环格 [*]-bzoj4200:[Noi2015]小园丁与老司机 [*]-bzoj1061:[Noi2008]志愿者招募 [*]-bzoj3600:没有人的算术 [*]-bzoj2806:[Ctsc2012]Cheat [*]-bzoj2219:数论之神 [*]-bzoj2595:[Wc2008]游览计划 [*]-bzoj

bzoj3713[PA2014]Iloczyn*

bzoj3713[PA2014]Iloczyn 题意: 判断给定的数字能否被表示成两个斐波那契数的乘积.n≤10^9 题解: 开始在想有没有什么根号级算法,后来想知道斐波那契数列10000位有多大,结果爆long long了……实际上斐波那契数列到45位就大于10^9了.所以直接枚举即可. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) fo

【BZOJ3721】PA2014 Final Bazarek 贪心

[BZOJ3721]PA2014 Final Bazarek Description 有n件商品,选出其中的k个,要求它们的总价为奇数,求最大可能的总价. Input 第一行一个整数n(1<=n<=1000000),表示商品数量.接下来一行有n个整数,表示每件商品的价格,范围在[1,10^9].接下来一行有一个整数m(1<=m<=1000000),表示询问数量.接下来m行,每行一个整数k[i](1<=k[i]<=n). Output 对于每个询问,输出一行表示保证奇数的

BZOJ 3709: [PA2014]Bohater

题目 3709: [PA2014]Bohater Time Limit: 5 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 507  Solved: 163[Submit][Status] Description 在一款电脑游戏中,你需要打败n只怪物(从1到n编号).为了打败第i只怪物,你需要消耗d[i]点生命值,但怪物死后会掉落血药,使你恢复a[i]点生命值.任何时候你的生命值都不能降到0(或0以下).请问是否存在一种打怪顺序,使得你可以

【HDOJ】4251 The Famous ICPC Team Again

划分树模板题目,主席树也可解.划分树. 1 /* 4251 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deq

BZOJ 3713: [PA2014]Iloczyn( 枚举 )

斐波那契数列<10^9的数很少很少...所以直接暴力枚举就行了... ------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #d