题解-UOJ 455雪灾与外卖
Problem
题意概要:一根数轴上有 \(n\) 只老鼠与 \(m\) 个洞,每个洞有费用与容量限制,要求每只老鼠要进一个洞且每个洞的老鼠不超过自身的容量限制,定义一种方案的费用为所有老鼠移动距离之和加上所有老鼠进的洞费用之和(若一个洞进了 \(k\) 只老鼠,则费用需要计算 \(k\) 次)
\(n,m\leq 10^5\)
Solution
冬令营时掉线了,只记得这题被大家把好评刷上去了
这题是所谓模拟费用流问题。我理解的模拟费用流其实等价于处理“反悔”也即反向弧,因为费用流问题是使用 最短路(贪心) 加 反向弧(反悔) 解决的,所以利用该种思想,在平时题目中,若贪心有瑕疵,可以考虑维护后悔操作。相似的题有bzoj4977跳伞逃生
将所有老鼠和洞按照坐标排序先
bzoj4977相当于这题中老鼠只能往左走,即只能往前匹配,这样可以从左往右维护一个堆解决贪心。
而这题中老鼠和洞都可能往右匹配,但是依照上述“贪心+后悔”的思想,考虑先让老鼠和洞往左匹配。
维护老鼠和洞两个堆,分别设为 \(A,B\);明确老鼠进洞的代价是两个坐标中靠右的减去靠左的。
下面开始讨论:
若当前为老鼠,且其坐标为 \(x\),若从 \(B\) 中取得的最优解为 \(v\),则对答案贡献 \(x+v\)。这样的话只考虑了向左的匹配,但实际有可能向右匹配(反悔),考虑将这次匹配的贡献消除,且将此点设定为左端,则需向 \(A\) 中加入 \(-(v+x)-x\)(前者将当前贡献消除,后者假定当前为左端点需减去)
若当前为餐厅,且其坐标为 \(y\),费用为 \(w\),若从 \(A\) 中取得的最优解为 \(v\),对答案贡献 \(w+y+v\),与上头类似,为了维护反悔操作需在 \(B\) 中加入 \(-(w+y+v)-y\)
打完后发现样例中有俩过不去,问了大神们才知道我少考虑了一种情况:若当前顺序为 鼠、洞、洞,我的方法一旦匹配了第一个洞和鼠后,不能考虑鼠反悔去匹配第二个洞的情况
那么就再加入一种反悔操作:往 \(A\) 中加入 \(-w-y\) 即可。具体地说,假设鼠价值 \(v\),两个洞的费用与坐标分别为 \(w_1,w_2,y_1,y_2\),那从第一种情况反悔到第二种情况的贡献为 \((w_2+y_2+v)-(w_1+y_1+v)=w_2+y_2-w_1-y_1\),由于 \(w_2+y_2\) 会在后面统计到,所以只需往堆中加入 \(-w_1-y_1\) 即可。至于为什么不需要对 洞、鼠、鼠 的情况做反悔,因为所有老鼠都是一样的,不可能存在舍近求远的情况
还有一点,由于所有老鼠都要求进洞,若最左侧的老鼠在最左侧的洞的左边,则这只老鼠有可能不会进洞,所以可以在最最最左侧加入一个费用无穷大的洞,这样左侧的老鼠匹配它后立马就会被替换掉,进而所有老鼠都会被匹配(在有解的情况下)
至于如何考虑每个洞的容量限制,可以将每个洞作为一个整体放进堆里,记录下剩余使用次数,作为反悔可以每次分裂一个出来
虽然思想比较简单,但是由于用到多次反悔操作(甚至有反悔后的反悔),所以代码难以调试,建议静态差错,最好一遍过
Code
代码中 \(P\) 表示老鼠,\(R\) 表示洞
//uoj-455
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <ll,int> pr;
#define mp make_pair
template <typename _tp> inline void read(_tp&x){
char c11=getchar(),ob=0;x=0;
while(c11!='-'&&!isdigit(c11))c11=getchar();if(c11=='-')ob=1,c11=getchar();
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;
}
const int N = 401000;
const ll Inf = 2e17;
int x[N],n,m;
struct node{
int y,w,c;
inline void in(){read(y),read(w),read(c);}
friend inline bool operator < (const node&A,const node&B) {return A.y < B.y;}
}p[N];
struct Heap{
pr h[N]; int tp;
inline bool empty() {return !tp;}
inline pr top() {return h[1];}
inline void push(pr x) {h[++tp] = x; push_heap(h+1,h+tp+1,greater <pr> ());}
inline void pop() {pop_heap(h+1,h+tp+1,greater <pr> ()); --tp;}
}R,P;
int main(){
read(n),read(m);
ll tot = 0;
for(int i=1;i<=n;++i) read(x[i]); sort(x+1,x+n+1);
for(int i=1;i<=m;++i) p[i].in(), tot += p[i].c; sort(p+1,p+m+1);
if(tot < n) {puts("-1"); return 0;}
R.push(mp(Inf,2e8));
x[n+1] = 2e9;
ll Ans = 0ll;
for(int i=1,j=1;i<=n or j<=m;) {
while(p[j].y <= x[i] and j <= m){
int usc = 0;
while(!P.empty() and p[j].c){
pr nw = P.top();
ll val = p[j].w + p[j].y + nw.first;
if(val > 0) break; P.pop();
int ct = min(nw.second, p[j].c);
Ans += (ll)ct * val;
R.push(mp(-nw.first - 2*p[j].y, ct));
p[j].c -= ct, usc += ct, nw.second -= ct;
if(nw.second) P.push(nw);
}
if(usc) P.push(mp(-p[j].w - p[j].y, usc));
if(p[j].c) R.push(mp(p[j].w - p[j].y, p[j].c));
++j;
}
if(i > n) continue;
pr nw = R.top(); R.pop();
Ans += nw.first + x[i];
P.push(mp(-(nw.first + x[i]) - x[i], 1));
--nw.second; if(nw.second) R.push(nw);
++i;
}
printf("%lld\n",Ans);
return 0;
}
题解-UOJ 455雪灾与外卖的更多相关文章
- [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
题目链接: [UOJ455]雪灾与外卖 题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c ...
- UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)
题目链接 http://uoj.ac/contest/47/problem/455 题解 模拟费用流,一个非常神奇的东西. 本题即为WC2019 laofu的讲课中的Problem 8,经典的老鼠进洞 ...
- uoj455 【UER #8】雪灾与外卖
http://uoj.ac/problem/455 题解: https://blog.csdn.net/litble/article/details/88410435 https://www.mina ...
- 【胡策篇】题解 (UOJ 192 + CF938G + SPOJ DIVCNT2)
和泉纱雾与烟花大会 题目来源: UOJ 192 最强跳蚤 (只改了数据范围) 官方题解: 在这里哦~(说的很详细了 我都没啥好说的了) 题目大意: 求树上各边权乘积是完全平方数的路径数量. 这种从\( ...
- 【UER #8】雪灾与外卖
题解: 这个东西的模型是个费用流 但是直接跑费用流能拿到5分的高分 $(nm)*(nm)*log{nm}$ 考虑优化一下建图 我们可以不用对每个店和人都连边 而是对人和店都连一条链 然后对每个人连店刚 ...
- UOJ 12 猜数 数学题
[UER #1]猜数 这一天,小Y.小D.小C正在愉快地玩耍. 小Y是个数学家,他一拍脑袋冒出了一个神奇的完全平方数 n. 小D是个机灵鬼,很快从小Y嘴里套出了 n 的值.然后在脑内把 n 写成了 a ...
- 【UTR #2】[UOJ#278]题目排列顺序 [UOJ#279]题目交流通道 [UOJ#280]题目难度提升
[UOJ#278][UTR #2]题目排列顺序 试题描述 “又要出题了.” 宇宙出题中心主任 —— 吉米多出题斯基,坐在办公桌前策划即将到来的 UOI. 这场比赛有 n 道题,吉米多出题斯基需要决定这 ...
- NOIWC2019 冬眠记
冬眠 由于THUWC考太差了没啥心情做事…… Day -1 报到日前一天晚上去看了看宿舍表,发现周围全是集训队,隔壁就是栋爷.高队和lca,再隔壁是zzq和wxh……吓傻了(本校buff这么好吗) D ...
- ZOJ - 3469 Food Delivery (区间dp)
When we are focusing on solving problems, we usually prefer to stay in front of computers rather tha ...
随机推荐
- 安装sql server2017出现错误:Visual Studio 运行时"Microsoft visual c++2017 X64 Minimum Runtime - 14.10.25008"需要修复
安装sql server 2017 Developer Edition时,安装选择“基本”,发生如下错误: 解决方法: 1.进入控制面板→程序中,找到“Microsoft visual c++2017 ...
- Python操作Excel 之 openpyxl
一.基础 安装openpyxl 模块 pip install openpyxl 或者通过轮子安装 font(字体类):字号.字体颜色.下划线等 fill(填充类):颜色等 border(边框类):设置 ...
- Tutorial 03_分布式数据库HBASE
(一)编程实现一下内容,并用Hadoop提供的Shell命令完成相同任务: 编程实现: (1)列出HBase所有表的相关信息,例如表名; package tutorial01; import java ...
- Python测试模块doctest
面试被问到了却没有用过,很尴尬:今天看了一下,真的是一个很简单的测试模块 方便起见,这里直接拿菜鸟教程的介绍和例子过来 开发高质量软件的方法之一是为每一个函数开发测试代码,并且在开发过程中经常进行测试 ...
- LODOP打印超过后隐藏内容样式
Lodop中的有纯文本和超文本,纯文本本身超过设置的打印项宽度,如果高度足够,就会换行,如果高度设置的很小,不会换行,后面的内容会直接隐藏.除非设置了多页项等,会自动分页.超文本打印项需要用css样式 ...
- python3的字符串和字节
Python3中内置类型bytes和str用法及byte和string之间各种编码转换 Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分.文本总是Unicode(16进制) ...
- HBuilderX——编译失败:HBuilderX 安装目录不能包括 ( 等特殊字符
前言 编译小程序的时候报错,原因其实很简单,安装目录的问题! 解决 我安装到了D:\Program Files (x86),放到D盘的根目录下或者D:\Program Files只要不包含一些特殊字符 ...
- leanote 信息栏显示笔记本和笔记类型
本文解决如下两个问题: 1. 在列表视图下使用搜索时,不知道搜出来的笔记属于哪个笔记本.(摘要视图下是有显示的) 2. 增加显示笔记类型(markdown 或 富文本) 修改resources\app ...
- python: c_char_p指向的bitmap图像数据,通过c_char_Array最终赋值给PIL的Image对象
def GetCurrentImage(self): ok, bitmap, buff_len = self.GetCurrentFrameBitmap() #调用C函数,返回位图数据的指针. bit ...
- pthread mutex 进程间互斥锁实例
共享标志 定义 名称 描述 0 PTHREAD_PROCESS_PRIVATE 进程内互斥锁 仅可当前进程内共享 1 PTHREAD_PROCESS_SHARED 进程间互斥锁 多个进程间共享 第一个 ...