很妙的一道题。
首先我们考虑将所有老鼠都进左边能进的且最优的洞。
然后有些老鼠其实是可以反悔的去选右边的洞,如果设第\(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); }