Title

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);
}
posted @ 2023-12-25 19:39  UncleSam_Died  阅读(38)  评论(0)    收藏  举报  来源