【ARC072F】 Dam 单调队列

题目大意:

有一个水库,容量为L,一开始是空的。有n天。

对于第i天,每天早上有vi单位的,水温为ti的水流进来。每天晚上你可以放掉一些水,多少自定。但是必须保证第二天水库不会溢出。

现在问,对于每个i,在使用最优放水策略的情况下,第i天水库是满的情况下最高水温(i之间互相独立)。混合后的温度计算就和混合溶液浓度一样计算。 
数据范围:n105,其它数109

 

由于这n天之间的方案是两两独立的,故在第p天之前,给第p天灌水的过程中,水库可不比灌满。

题目要求要在第p天注满整个水库,那么水库中显然会储有第p天前某些天注入的水。

我们不妨用一个关于水温的单调递增队列,存储下前p天的注水信息,这些水的体积恰好为L

当第p天的水被注入前,我们要提前放掉一些水,显然我们要放掉最早加入,且水温最低的那批水(位于队头),删除方法详见代码。

对于第p天的注水(Vp,Tp)我们比较队尾的注水信息Vtail,Ttail,若存在Vp>Vtail那么我们直接将第p天的注水信息放到队列尾即可。

否则,我们就将第p天的注水与队尾的注水进行混合,用混合后的注水信息更新队尾,更新方法详见代码。

更新完毕后,taili=headViL即为答案。

 

不难发现,每次注水的信息最多往单调队列中塞入一次,删除也是最多一次,故时间复杂度是O(n)

复制代码
 1 #include<bits/stdc++.h>
 2 #define M 500005
 3 using namespace std;
 4 struct node{double t,v;}q[M]={0},p;
 5 int head=0,tail=0;
 6 int main(){
 7     double l=0,ll=0,now=0;
 8     int n; scanf("%d",&n);
 9     scanf("%lf",&ll); l=ll;
10     while(n--){
11         scanf("%lf%lf",&p.t,&p.v);
12         while(p.v>l){
13             if(q[head].v+l<=p.v)
14             now-=q[head].v*q[head].t,l+=q[head++].v;
15             else{
16                 double x=p.v-l;
17                 now-=x*q[head].t;
18                 l+=x;
19                 q[head].v-=x;
20             }
21         }
22         l-=p.v; now+=p.v*p.t; q[++tail]=p;
23         while(head<tail&&q[tail-1].t>=q[tail].t){
24             q[tail-1].t=(q[tail-1].t*q[tail-1].v+q[tail].t*q[tail].v)/(q[tail-1].v+q[tail].v);
25             q[tail-1].v+=q[tail].v;
26             tail--;
27         }
28         printf("%.10lf\n",now/ll);
29     }
30 }
复制代码

 

 

posted @   AlphaInf  阅读(289)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)
点击右上角即可分享
微信分享提示