2019.7.16 义乌模拟赛 T4 老鼠进洞
很妙的一道题。
首先我们考虑将所有老鼠都进左边能进的且最优的洞。
然后有些老鼠其实是可以反悔的去选右边的洞,如果设第\(i\)只老鼠原来连\(j\),反悔去连\(k\),那么对答案的贡献就是\(p_k-2x_i+p_j\)
可以发现这个东西对\(k\)独立,那么我们用一个堆维护即可。
但是一个洞也可以反悔不去选那个老鼠,这样我们对洞也建一个堆这样维护即可。时间复杂度\(O(nlogn)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 1000000
#define M 5000
#define mod 1000000000
#define eps (1e-7)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,k,cnt,pus;ll ans,tot;
I void read(int &x){
char s=Gc();x=0;int f=1;while(s<'0'||s>'9')s=='-'&&(f=-1),s=Gc();
while(s>='0'&&s<='9') x=x*10+s-48,s=Gc();x*=f;
}
struct yyy{int w,c;}S[N+5];I bool cmp(yyy x,yyy y){return x.w<y.w;}
struct ques{int w,flow;bool operator <(const ques &s)const{return w>s.w;};}now;
priority_queue<ll,vector<ll>,greater<ll> > Q1;priority_queue<ques> Q2;
int main(){
freopen("mice.in","r",stdin);freopen("mice.out","w",stdout);
re int i;read(n);read(m);k=n+m;for(i=1;i<=n;i++) scanf("%d",&S[++cnt].w),S[cnt].c=-1;for(i=1;i<=m;i++) ++cnt,read(S[cnt].w),read(S[cnt].c),tot+=S[cnt].c;
if(tot<n) return printf("-1\n"),0;sort(S+1,S+cnt+1,cmp);for(i=1;i<=cnt;i++){
if(~S[i].c){
while(!Q1.empty()&&S[i].c&&Q1.top()+S[i].w<0)tot=Q1.top()+S[i].w,Q1.pop(),ans+=tot,Q2.push((ques){-S[i].w-tot,1}),S[i].c--;
S[i].c&&(Q2.push((ques){-S[i].w,S[i].c}),0);
}
else{
tot=1e14;if(!Q2.empty())now=Q2.top(),tot=now.w+S[i].w,Q2.pop(),now.flow--,now.flow&&(Q2.push(now),0);ans+=tot,Q1.push(-tot-S[i].w);
}
}printf("%lld\n",ans);
}