题目大意
有个水库,最多能存L单位水,一开始是空的,对于n天,每天早上有v[i]单位的,水温为t[i]的水流进来。每天晚上你可以放掉一些水,多少自定。但是必须保证第二天水库不会溢出。现在问,对于每个i,在使用最优放水策略的情况下,第i天水库是满的情况下最高水温(i之间互相独立)。混合后的温度计算就和混合溶液浓度一样计算。
n<=1e5,其他数1e9范围内
解题思路
似乎有点无从下手。
对于某个i,它的前几天肯定是都要影响到他的。如果每天进水的温度逐渐增加,肯定是取最后几天的水,前面的水全部放空。
我们脑洞一下,先顺着进水。我们先不混合,搞个温度单调递增的队列维护每天的水。考虑加入第i天的水。如果水体积爆了L,肯定要踢掉前面的,因为当前的最后一天的水是不能排掉的。也是因为这样,如果这天水温度不够队列末尾高,我们就把它末尾混在一起。发现这样并没有什么问题….
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
typedef double db;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
const int N=1e6+5,mo=998244353;
struct rec
{
ll v;
db t;
}s[N];
ll sum,t[N],v[N],l,r,n,L,prod,i,dec;
int main()
{
freopen("t17.in","r",stdin);
scanf("%lld %lld",&n,&L);
l=1;
r=0;
fo(i,1,n)
{
scanf("%lld %lld",t+i,v+i);
while (sum+v[i]>L)
{
dec=min(s[l].v,sum+v[i]-L);
s[l].v-=dec;
sum-=dec;
prod-=dec*s[l].t;
if (!s[l].v) l++;
}
s[++r]={v[i],t[i]};
prod+=v[i]*t[i];
sum+=v[i];
while (l<r&&s[r].t<s[r-1].t)
{
s[r-1].t=(s[r-1].t*s[r-1].v+s[r].t*s[r].v)/(s[r-1].v+s[r].v);
s[r-1].v+=s[r].v;
r--;
}
printf("%lf\n",(db)prod/L);
}
}