[UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
题目链接:
题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c_{i}$个送餐员,一个送餐员去一个餐厅的代价为$|x_{i}-y_{j}|+w_{j}$,求最小代价。
首先这个题可以暴力建图跑费用流,具体做法就不说了。现在我们考虑模拟费用流的过程,也就是模拟贪心及匹配中反悔的过程。
我们对送餐员和餐厅分别开一个小根堆然后从左往右决策每个坐标位置的人或餐厅的选择:
对于送餐员,先强制让他与左面的餐厅匹配(如果没有则看作和无限远处匹配),为了使代价最小,我们选择左面$w-y$最小的餐厅与他匹配,因为他还可能与右边的餐厅匹配,所以我们往送餐员的堆中加入一个当前送餐员的反悔操作,权值为$-(x-y+w)-x$(因为这个反悔操作只会匹配右边的餐厅,所以送餐员之后的权值为$-x$),这样如果之后选择这个反悔操作,就会将之前选择的代价抵消掉,并让这个送餐员产生新的代价。这也就是说送餐员的堆中存的都是反悔的送餐员。
对于餐厅,只要当前餐厅的权值$w+y$与送餐员的堆顶的权值之和小于$0$就说明这个堆顶的送餐员匹配当前餐厅比之前的选择更优,那么我们就让他匹配当前餐厅。这时候有两种情况:1、餐厅反悔,它要匹配它右边的送餐员,那么我们在餐厅的堆中加入权值为$-(v+w+y)+w-y$的反悔操作(其中$v$表示送餐员堆顶的权值,因为这个反悔操作只会匹配右边的送餐员,所以餐厅的权值为$w-y$)。2、送餐员反悔,他要匹配更右边的餐厅,这时就要在送餐员的堆中加入权值为$-w-y$的反悔操作来使下一次选到这个操作时抵消掉这次匹配的代价。
总的来说这道题就是在所有正常匹配和反悔操作中贪心寻找最优解来进行匹配。
最后说一下时间复杂度:因为对于送餐员向左匹配时只会反悔一次所以送餐员的反悔操作进堆次数是线性的。对于餐厅的操作,因为一个餐厅匹配左面的送餐员时送餐员的反悔操作权值都是$-y-w$,所以只需要记录一下匹配数量,统一入堆即可。每个反悔操作在被匹配后都会删除,而除了送餐员向左匹配的反悔操作之外,只会在枚举到每个餐厅时将一个权值入堆,所以总共能被匹配的送餐员反悔操作的数量是线性的。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct miku
{
ll sum;
ll num;
miku(){}
miku(ll SUM,ll NUM){sum=SUM,num=NUM;}
};
bool operator <(miku a,miku b){return a.sum>b.sum;}
priority_queue<miku>A,B;
ll x[100010];
ll y[100010];
ll w[100010];
ll c[100010];
int n,m;
ll ans;
void ins1(ll x)
{
ll v=B.top().sum;
int c=B.top().num;
B.pop();
ans+=x+v;
A.push(miku(-(x+v)-x,1));
if(c>1)
{
B.push(miku(v,c-1));
}
}
void ins2(ll y,ll w,int c)
{
int k=0;
while(!A.empty()&&k<c&&A.top().sum+w+y<0)
{
ll v=A.top().sum;
int s=A.top().num;
A.pop();
int g=min(s,c-k);
s-=g,k+=g,ans+=1ll*g*(v+w+y);
if(s)
{
A.push(miku(v,s));
}
B.push(miku(-(v+w+y)+w-y,g));
}
if(k)
{
A.push(miku(-y-w,k));
}
if(c-k)
{
B.push(miku(w-y,c-k));
}
}
int main()
{
scanf("%d%d",&n,&m);
ll tot=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&x[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&y[i],&w[i],&c[i]);
tot+=c[i];
}
if(tot<n)
{
printf("-1");
return 0;
}
y[0]=-1ll<<60,c[0]=1<<30;
int i=1,j=0;
while(i<=n&&j<=m)
{
if(x[i]<=y[j])
{
ins1(x[i]);
i++;
}
else
{
ins2(y[j],w[j],c[j]);
j++;
}
}
while(i<=n)
{
ins1(x[i]);
i++;
}
while(j<=m)
{
ins2(y[j],w[j],c[j]);
j++;
}
printf("%lld",ans);
}
[UOJ455][UER #8]雪灾与外卖——堆+模拟费用流的更多相关文章
- BZOJ4977[Lydsy1708月赛]跳伞求生——贪心+堆+模拟费用流
题目链接: 跳伞求生 可以将题目转化成数轴上有$n$个人和$m$个房子,坐标分别为$a_{i}$和$b_{i}$,每个人可以进一个他左边的房子,每个房子只能进一个人.每个房子有一个收益$c_{i}$, ...
- BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流
题目链接: [Noi2017]蔬菜 题目大意:有$n$种蔬菜,每种蔬菜有$c_{i}$个,每种蔬菜每天有$x_{i}$个单位会坏掉(准确来说每天每种蔬菜坏掉的量是$x_{i}-$当天这种蔬菜卖出量), ...
- 模拟费用流 & 可撤销贪心
1. CF730I Olympiad in Programming and Sports 大意: $n$个人, 第$i$个人编程能力$a_i$, 运动能力$b_i$, 要选出$p$个组成编程队, $s ...
- UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)
题目链接 http://uoj.ac/contest/47/problem/455 题解 模拟费用流,一个非常神奇的东西. 本题即为WC2019 laofu的讲课中的Problem 8,经典的老鼠进洞 ...
- 【bzoj1150】[CTSC2007]数据备份Backup 模拟费用流+链表+堆
题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏 ...
- 【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)
[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sam ...
- luogu P5470 [NOI2019]序列 dp 贪心 费用流 模拟费用流
LINK:序列 考虑前20分 容易想到爆搜. 考虑dp 容易设\(f_{i,j,k,l}\)表示前i个位置 选了j对 且此时A选择了k个 B选择了l个的最大值.期望得分28. code //#incl ...
- 贪心(模拟费用流):NOIP2011 观光公交
[问题描述] 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0 分钟出现在1号景点,随后依次前往2. ...
- BZOJ4849[Neerc2016]Mole Tunnels——模拟费用流+树形DP
题目描述 鼹鼠们在底下开凿了n个洞,由n-1条隧道连接,对于任意的i>1,第i个洞都会和第i/2(取下整)个洞间有一条隧 道,第i个洞内还有ci个食物能供最多ci只鼹鼠吃.一共有m只鼹鼠,第i只 ...
随机推荐
- Java线程池实现原理与技术(ThreadPoolExecutor、Executors)
本文将通过实现一个简易的线程池理解线程池的原理,以及介绍JDK中自带的线程池ThreadPoolExecutor和Executor框架. 1.无限制线程的缺陷 多线程的软件设计方法确实可以最大限度地发 ...
- mybatis抽取出的工具-(一)通用标记解析器(即拿即用)
目录 1. 简介 1.1 mybatis-config.xml 中使用 1.2 xxxMapper.xml 中使用 2. 原理 2.1 GenericTokenParser 成员变量 2.2 Gene ...
- .net core 监听性能,异常
https://www.cnblogs.com/laozhang-is-phi/p/10287023.html#autoid-2-2-0
- 基于Tornado签名cookie源码设计API认证
想法1 服务端客户端个保存相同的一串字符串,客户端发送API请求时带着这段字符串来我服务端做校验,通过则返回相应数据,否则拒绝访问 弊端 黑客截取到请求信息,可直接会获取到该字符串,想服务端发送请求并 ...
- Python 内置库 sys用法
sys模块功能众多,这边先学习几个常用的方法sys常见函数列表① sys.argv: 实现从程序外部向程序传递参数.其实sys.argv[]就是一个列表,里面的项为用户输入的参数,但是sys.argv ...
- 移动web、webApp、混合APP、原生APP、androd H5混合开发 当无网络下,android怎么加载H5界面
PhoneGap是一个采用HTML,CSS和JavaScript的技术,创建移动跨平台移动应用程序的快速开发平台.它使开发者能够在网页中调用IOS,Android,Palm,Symbian,WP7,W ...
- c#中用sql存储过程
string connstr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionStri ...
- tomcat启动参数
/usr/java/jdk1..0_191-amd64/bin/java -Djava.util.logging.config./conf/logging.properties -Djava.util ...
- MySQL之慢查询日志和通用查询
MySQL中的日志包括:错误日志.二进制日志.通用查询日志.慢查询日志等等.这里主要介绍下比较常用的两个功能:通用查询日志和慢查询日志. 1.通用查询日志:记录建立的客户端连接和执行的语句. 2.慢查 ...
- jmeter环境配置
Java 8 安装 正常安装,一路默认就好,记住安装路径,配置环境变量时用得到.默认安装路径:C:\Program Files\Java\jdk1.8.0_91. 安装好之后会有两个文件夹一个是jdk ...