Dam
Problem Statement
有个水库,最多能存LL单位水,一开始是空的,对于天,每天早上有vivi单位的,水温为titi的水流 进来。每天晚上你可以放掉一些水,多少自定。但是必须保证第二天水库不会溢出。现在 问,对于每个ii,在使用最优放水策略的情况下,第天水库是满的情况下最高水温(每次询问 之间互相独立)。
v1v1体积t1t1水温和v2v2体积t2t2水温的水混在一起得到的新的水温为(t1t1∗v1v1+t2t2∗v2v2)/(v1v1+v2v2)
Data Constraint
nn<=,其他数109109范围内
Solution
维护一个进水序列,从前往后做,如果新加入的水比前面水温更大,则直接加到队尾,否则一 定是不停往前合并使得自己的水温变高使后面的答案更大。
显然这样做是对的。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
typedef double db;
const ll N=6e5+7;
ll d[N],M;
db t[N];
int n;
inline ll max(ll a,ll b)
{return a>b?a:b;}
inline ll read()
{
ll o=0; char ch=' ';
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
return o;
}
int main()
{
cin>>n>>M;
int r=0,l=1,ok=0;
db zl=0;
fo(i,1,n)
{
ll T=read(),V=read();
d[++r]=V; t[r]=(db)T*V;
zl+=t[r]; ok+=d[r];
for(;t[r]/d[r]<t[r-1]/d[r-1]&&l<r;--r)
if(d[r-1]+d[r]<=M)t[r-1]=t[r-1]+t[r],d[r-1]+=d[r];
else{
t[r-1]=t[r]+(t[r-1]/d[r-1])*(M-d[r]);
ok=d[r-1]=M; zl=t[r-1]; --r; l=r;
break;
}
for(;ok>M;++l)
if(ok-d[l]>=M)ok-=d[l],zl-=t[l];
else{
db every=t[l]/d[l];
zl-=every*(ok-M);
t[l]-=every*(ok-M);
d[l]=d[l]-(ok-M);
ok=M; break;
}
printf("%.7lf\n",zl/M);
}
}