zoukankan      html  css  js  c++  java
  • CodeForces 797F Mice and Holes

    传送门

    题目大意

    直线上有$N$头老鼠要走入洞,一共$M$个洞,每个洞最多能容纳$r_i$头老鼠。

    现在你要让每个老鼠洞进洞,求所有老鼠进洞的距离之和最小值。

    原题$n,mleq 5000$,先加强版$n,mleq 10^6$。

    题解

    贪心

    将所有的洞和坐标横坐标排序,从左往右依次考虑。

    若当前为位于$pos$的老鼠,那么它一定会去匹配之前的洞(如果有的话)

    用堆维护每个洞的坐标和容量,找到坐标之前最大的洞,计算它的距离加入贡献,同时记录一下它到之前的距离$rg$。

    再用一个堆维护每一个$rg+pos$,如果有一个洞出现在$kin [pos,pos+rg)$,那么一定会让位于$pos$的老鼠进入$k$的洞,因为这样会更优。

    若当前为位于$k$洞,那么它一定会去找之前的老鼠,对于$k<pos+rg$的所有老鼠,尽量地钦定它们进入这个洞,这样减少的代价恰好为$dt=pos+rg-k$。但是有的时候需要让这些老鼠“反悔”,因为后面的老鼠可能更需要这些洞,所以每以$k<pos+rg$的方式更新一个老鼠,就要多存一个坐标为$k-dt$,容量为$1$的洞,因为后面的老鼠需要进入这个洞的话必须让选择它的老鼠再找回那减少的代价$dt$,所以干脆直接让距离比之前更远$dt$即可。

    #include<bits/stdc++.h>
    #define P pair<LL,int>
    #define fs first
    #define sc second
    #define LL long long
    #define M 2000010
    #define INF 200000100000000ll
    using namespace std;
    namespace IO{
    	const int BS=(1<<20)+5; int Top=0;
    	char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
    	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
    	void flush(){fwrite(OT,1,OS-OT,stdout);}
    	void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
    	void write(int x){
    		if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
    		while(x) SS[++Top]=x%10,x/=10;
    		while(Top) Putchar(SS[Top]+'0'),--Top;
    	}
    	int read(){
    		int nm=0,fh=1; char cw=Getchar();
    		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
    		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
    		return nm*fh;
    	}
    }using namespace IO;
    int n,m; LL tot,ans; P p[M];
    priority_queue<LL> K;
    priority_queue<P> W; 
    void ins(LL pos){
    	LL rg=INF;
    	if(!W.empty()){
    		P now=W.top(); W.pop();
    		rg=pos-now.fs,now.sc--;
    		if(now.sc) W.push(now);
    	}K.push(pos+rg),ans+=rg;
    }
    void pvd(P now){
    	while(now.sc&&!K.empty()&&K.top()>now.fs){
    		LL dis=K.top()-now.fs; ans-=dis;
    		now.sc--,K.pop(),W.push(P(now.fs-dis,1));
    	}if(now.sc) W.push(now);
    }
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) p[i].fs=read(),p[i].sc=-1;
    	for(int i=n+1;i<=n+m;i++) p[i].fs=read(),tot+=(p[i].sc=read());
    	if(tot<n){puts("-1");return 0;}sort(p+1,p+n+m+1);
    	for(int i=1;i<=n+m;i++) p[i].sc==-1?ins(p[i].fs):pvd(p[i]);
    	printf("%lld
    ",ans); return 0;
    }
  • 相关阅读:
    thinkphp分页样式css代码
    thinkphp两表,多表联合查询及分页的连贯操作写法
    ThinkPHP3.2.3新特性之:数据库设置
    ThinkPHP的主从数据库配置
    CentOS7 64位下MySQL5.7安装与配置(YUM)
    sessionid如何产生?由谁产生?保存在哪里?
    GIT使用
    Windows下安装composer
    树莓派debian配置lamp[解决Apache不显示php网页]
    【Linux】Debian 下安装 Apache,MySQL,PHP
  • 原文地址:https://www.cnblogs.com/OYJason/p/9884074.html
Copyright © 2011-2022 走看看