Dam
Problem Statement
有个水库,最多能存
L
L
单位水,一开始是空的,对于天,每天早上有
vi
v
i
单位的,水温为
ti
t
i
的水流 进来。每天晚上你可以放掉一些水,多少自定。但是必须保证第二天水库不会溢出。现在 问,对于每个
i
i
,在使用最优放水策略的情况下,第天水库是满的情况下最高水温(每次询问 之间互相独立)。
v1
v
1
体积
t1
t
1
水温和
v2
v
2
体积
t2
t
2
水温的水混在一起得到的新的水温为(
t1
t
1
∗
v1
v
1
+
t2
t
2
∗
v2
v
2
)/(
v1
v
1
+
v2
v
2
)
Data Constraint
n n <=,其他数 109 10 9 范围内
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);
}
}