CF954E Water Taps 题解
解题思路
其实题目翻译中已经给出一些提示了。
显然,对于式子 $\displaystyle \frac{\displaystyle\sum_{i=1}^n x_i\times t_i}{\displaystyle \sum_{i=1}^n x_i}=T$,我们稍加变形就可以得到 $\displaystyle \sum_{i=1}^n x_i\times(t_i-T)=0$。考虑在读入的时候,对于每一个 $i\in [1,n]$,进行操作 $t_i\gets t_i-T$,那么这时的式子即转变为 $\displaystyle \sum_{i=1}^n x_i\times t_i=0$。
观察可以发现,在有解的条件下,只有三种 $t_i$ 的取值可以满足:
- $\forall i\in[1,n]$,$t_i=0$;
- $\forall i \in [1,n]$,一部分 $t_i>0$ 剩下的 $t_i<0$;
- $\forall i \in [1,n]$,一部分 $t_i>0$ ,一部分 $t_i<0$,其余的 $t_i=0$;
将这三种情况综合一下,可以发现只需要第三种情况,那么当 $t_i=0$ 时,$x_i\times t_i=0$,即这个水龙头无论出多少水,对式子的成立情况都没有影响。那么,我们可以直接让这些水龙头的出水取最大值 $a_i$,在接下来的步骤中排除这些水龙头即可。
对于剩下的水龙头,我们考虑按照温度从小到大排序后双指针,设当 $i=c$ 时,$t_i<0$ 且 $t_{i+1}>0$,那么,我们令 $l=c$,$r=c+1$,分别向 $1$ 和 $m$ 移动,其中 $m$ 是 $t_i$ 不为 $0$ 的水龙头的数量。分以下三种情况考虑:
- $a_l\times t_l+a_r\times t_r<0$ ,也就是说,如果此时 $l$ 和 $r$ 水龙头均打开到最大值,那么温度将低于 $0$(减去后的温度),因此,选择将 $r$ 开到最大值,同时调节 $l$,使得温度恰好为 $0$。由于 $l$ 仍然存在一些水量进行分配,那么我们将 $r$ 向右移动一位,同时把 $l$ 的剩余的水量 $a_l\gets a_l-(-\frac{(a_r\times a_t)}{t_l})$;
- $a_l\times t_l+a_r\times t_r>0$ ,也就是说,如果此时 $l$ 和 $r$ 水龙头均打开到最大值,那么温度将高于 $0$(减去后的温度),因此,选择将 $l$ 开到最大值,同时调节 $r$,使得温度恰好为 $0$。由于 $r$ 仍然存在一些水量进行分配,那么我们将 $l$ 向左移动一位,同时把 $r$ 的剩余的水量 $a_r\gets a_r-(-\frac{(a_l\times a_l)}{t_r})$;
- $a_l\times t_l+a_r\times t_r=0$,两个水龙头均开到最大,并同时分别向左、右移动一。
AC 代码
代码进行防抄袭处理,勿直接 copy。
#include<math.h>
#include<time.h>
#include<stdio.h>
#include<algorithm>
#define ll long long
#define N 200005
#define eps 1e-15
int n;double T,t[N],a[N];
struct Tap{
double t;
double a;
}tap[N];int m;
inline bool cmp(Tap A,Tap B){
return A.t<B.t;
}signed main(){
scanf("%d%lf",&n,&T);
for(register int i=1;i<=n;++i)
scanf("%lf",&a[i]);
for(register int i=1;i<=n;++i)
scanf("%lf",&t[i]);
for(register int i=1;i<=n;++i)
t[i]=t[i]-T;
double ans=0.0;
for(register int i=1;i<=n;++i){
if(fabs(t[i])<=eps)
ans+=a[i];
else tap[++m]={t[i],a[i]};
}std::sort(tap+1,tap+m+1,cmp);
int l=1,r=m;
while(tap[l].t+eps<=0) ++l;--l;
while(tap[r].t+eps>=0) --r;++r;
while(l>=1&&r<=m){
double _1=tap[l].a*tap[l].t;
double _2=tap[r].a*tap[r].t;
if(_1+_2+eps<0){
tap[l].a-=-_2/tap[l].t;
ans+=tap[r].a-_2/tap[l].t;
++r;
}else if(_1+_2-eps>0){
tap[r].a-=-_1/tap[r].t;
ans+=tap[l].a-_1/tap[r].t;
--l;
}else{
ans+=tap[l].a;
ans+=tap[r].a;
--l,++r;
}
}printf("%12.lf",ans);
}

浙公网安备 33010602011771号