【ARC072F】 Dam 单调队列
题目大意:
有一个水库,容量为L,一开始是空的。有n天。
对于第i天,每天早上有vi单位的,水温为ti的水流进来。每天晚上你可以放掉一些水,多少自定。但是必须保证第二天水库不会溢出。
现在问,对于每个i,在使用最优放水策略的情况下,第i天水库是满的情况下最高水温(i之间互相独立)。混合后的温度计算就和混合溶液浓度一样计算。
数据范围:n≤105,其它数≤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 }
分类:
单调队列
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 用 C# 插值字符串处理器写一个 sscanf
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!