Description
有一天Masha回到家,发现有n只老鼠在它公寓的走廊上,她大声呼叫,所以老鼠们都跑进了走廊的
洞中。
这个走廊可以用一个数轴来表示,上面有n只老鼠和m个老鼠洞。第i只老鼠有一个坐标x i ,第j个洞有
一个坐标p j 和容量c j 。容量表示最多能容纳的老鼠数量。
找 到 让 老 鼠 们 全 部 都 进 洞 的 方 式,使 得 所 有 老 鼠 运 动 距 离 总 和 最 小。 老 鼠i进 入 洞j的 运 动 距 离
为|x i − p j |
无解输出-1。
solution
正解:调整贪心
还是老套路,在能使得答案更小时,我们就直接决策,并加入后悔操作,在这个题目中,我们将老鼠和老鼠洞排个序,然后扫描,开两个堆:老鼠堆和老鼠洞堆.
如果碰到老鼠,我们直接把他丢进最近的一个洞中,计算答案 \(x[i]-p[j]\) 并且将 \(x[i]+x[i]-p[j]\) 丢入老鼠堆中.
如果碰到老鼠洞,我们一直把前面能够使得答案更小的老鼠都加入到这个洞中,并且把后悔操作丢入老鼠洞的堆中.
巧妙的是:处理限制的方法:我们在用掉一次老鼠洞后,我们判断是否有剩余容量,如果有,我们再加入一次堆即可
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#define RG register
using namespace std;
typedef long long ll;
const int N=2000005;
const ll inf=2e15;
inline int gi(){
RG int str=0;RG char ch=getchar();bool h=0;
while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar();
if(ch=='-')h=1,ch=getchar();
while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
return h?-str:str;
}
#define x first
#define y second
int n,m;
struct node{
ll x;int y;
node(){}
node(ll _x,int _y){x=_x;y=_y;}
bool operator <(const node &pr)const{return x<pr.x;}
};
pair<ll,int>p[N];
priority_queue<ll>qm;
priority_queue<node>qd;
void work()
{
int tot=0,x,y,j;ll sum=0;
cin>>n>>m;
for(int i=1;i<=n;i++)p[++tot]=make_pair(gi(),-1);
for(int i=1;i<=m;i++){
x=gi();y=gi();sum+=y;
p[++tot]=make_pair(x,y);
}
if(sum<n){puts("-1");return ;}
sort(p+1,p+tot+1);
ll w,ans=0;
for(RG int i=1;i<=tot;i++){
if(p[i].y==-1){
w=inf;
if(!qd.empty()){
w=p[i].x-qd.top().x;j=qd.top().y;qd.pop();
if(p[j].y)p[j].y--,qd.push(node(p[j].x,j));
}
ans+=w;
qm.push(p[i].x+w);
}
else{
while(!qm.empty() && p[i].y && p[i].x-qm.top()<0){
w=p[i].x-qm.top();
p[i].y--;qm.pop();
qd.push(node(p[i].x+w,0));
ans+=w;
}
if(p[i].y)p[i].y--,qd.push(node(p[i].x,i));
}
}
cout<<ans<<endl;
}
int main()
{
work();
return 0;
}