Problem
有 个人,第 人坐标为 。有 家餐厅,第 家坐标为 ,且人数限制 ,有附加权值 。
第 个人进第 家餐厅的费用为 ,求使每个人都进餐厅的最小费用。
Solution
我不会模拟,更不会费用流。。我为啥要搞模拟费用流???思维难度又高又难调,我这种无脑选手压根吃不消啊 TAT
先从费用流的模型出发,我们可以直接在坐标轴上建出一张图,相邻的点进行连边,餐厅和人分别连向S和T。这样直接跑费用流就可以得到25分的好成绩啦!
为了优化,我们就需要优化跑费用流的过程。大体的思路是把人和餐厅全部都按照坐标进行排序,当扫到一个人/餐厅时,我们考虑它能否和前面的进行匹配,或者替代前面的某些匹配关系。由于人要强制匹配,不妨新建一个坐标在 ,价值和数量都是 的餐厅,后来再被替代,这样人就一定在匹配中了。
我们用第一个堆维护人的决策,第二个维护餐厅的决策。
考虑一个人,如果和前面的一个餐厅匹配,花费就是 ,那么用第一个小根堆维护 的最小值。匹配了之后,有可能需要反悔,考虑反悔后的花费为 ,那么我们就需要把 丢进第二个小根堆中供后来的餐厅匹配。
考虑一家餐厅,若它和前面的第 个人发生了替代,那么花费就变成了 ,那么如果与第二个堆的堆顶能产生一个负的费用的话,我们就选择替代。这个餐厅也可能被替代,反悔时需要补回这个被匹配的人的信息,那么补一个 的差值,重新丢回第二个堆维护即可。除此之外,这个餐厅的决策还可能被后面的人替代,为了丢进第一个堆中,补上差值 。
然而你会发现这样复杂度似乎有点问题,如果从前到后,餐厅一个比一个更优,那么每个人的决策都会被不断替代,复杂度高达 。注意到被同一家餐厅所替代的人所补的差值均相同,把这些决策合并。每次最多分裂出一个状态,势能分析一下复杂度就是 。
耐心调试,祝身体健康。。
Code
#include <functional>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=400010,INF=0x3f3f3f3f;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
struct node{
int x,w,c;
bool operator < (const node &b)const{return x<b.x;}
}p[maxn];
struct data{
ll v;int f;
data(const ll _v=0ll,const int _f=0){v=_v;f=_f;}
bool operator > (const data &b)const{return v==b.v?f>b.f:v>b.v;}
};
int n,m,tot,x,w,c,f,tmp,s;
ll sum,v,ans;
struct Heap{
int p;data a[maxn];
void push(data x){a[++p]=x;push_heap(a+1,a+p+1,greater<data>() );}
void pop(){pop_heap(a+1,a+p+1,greater<data>() );--p;}
}H1,H2;
int main()
{
read(n);read(m);tot=n;
for(int i=1;i<=n;i++) read(p[i].x);
for(int i=1;i<=m;i++)
{
read(x);read(w);read(c);
getmin(c,n);sum+=c;
if(c) p[++tot]=(node){x,w,c};
}
if(sum<n){puts("-1");return 0;}
p[++tot]=(node){-INF,INF,n};
sort(p+1,p+tot+1);
for(int i=1;i<=tot;i++)
{
x=p[i].x;w=p[i].w;c=p[i].c;
if(c)
{
s=0;
while(c&&H1.p)
{
v=H1.a[1].v;f=H1.a[1].f;
if(v+w+x>=0) break;
H1.pop();tmp=min(c,f);
ans+=(v+w+x)*tmp;
s+=tmp;c-=tmp;f-=tmp;
H2.push(data(-v-x-x,tmp));
if(f) H1.push(data(v,f));
}
if(s) H1.push(data(-w-x,s));
if(c) H2.push(data(w-x,c));
}
else
{
v=H2.a[1].v;f=H2.a[1].f-1;H2.pop();
ans+=x+v;
H1.push(data(-v-x-x,1));
if(f) H2.push(data(v,f));
}
}
printf("%lld\n",ans);
return 0;
}