【BZOJ4654】【NOI2016】国王饮水记(动态规划,斜率优化)
【BZOJ4654】【NOI2016】国王饮水记(动态规划,斜率优化)
题面
题解
首先肯定是找性质。
明确一点,比\(h_1\)小的没有任何意义。
所以我们按照\(h\)排序,那么\(h_1\)就是当前\(1\)号位置的水量。
假设我们使用的次数不受到任何限制,我们思考怎么样才是最优。
首先每次只和一个合并一定比和多个合并更优。
假设有三个位置\(h_1\lt h_2\lt h_3\)
那么如果直接合并,答案是\((h_1+h_2+h_3)/3\)
如果每次合并一个,答案是\(((h_1+h_2)/2+h_3)/2=(h_1+h_2)/4+h_3/2\)
显然后者更优。
同理,通过后面那个式子,我们发现先和\(h_2\)合并比先和\(h_3\)合并更优。
所以,在合并次数不受到限制的时候,我们显然是从小往大,依次合并。
当次数不够的时候,我们肯定不能只合并一个位置,显然合并所有位置还是更优的。
那么,既然不能够一个个合并,所以只能够把若干次合并放在一起做。
因为每次和后面的若干个做完合并之后,这些一起合并的位置就可以直接丢掉了,
再因为从小往大合并更优,假设\(h_i\)已经有序,那么每次一定是和一段合并。
所以设\(f[i][j]\)表示前面\(i\)个位置合并了\(j\)次的最优值。
那么考虑转移\(f[i][j]=max((f[k][j-1]+\sum_{x\in[k+1,i]}h_x)/(i-k+1)\)
这样的复杂度\(O(n^2k)\),\(k\)是可以合并的次数。
把式子重写,\(\sum\)写成前缀和的形式,暂时忽略后面的枚举次数
\(f[i]=(f[k]+s[i]-s[k])/(i-k+1)\)
这个式子很像斜率:
\((s[i]-(s[k]-f[k]))/(i-(k-1))\)
相当于把前面所有已知状态看成一个点\((k-1,s[k]-f[k])\)
那么找到当前点\((i,s[i])\)到这个点的斜率,使其斜率最大,可以斜率优化解决。
这样可以在凸包上三分计算,时间复杂度\(O(nklog_3n)\)
因为给定的高精小数库还有一个\(O(p)\)的复杂度,所以整个的复杂度是\(O(nkplogn)\)
同时还发现具有决策单调性,所以可以做到\(O(nkp)\)
决策单调性的证明大概是这样的,假设当位置是\((i,s[i])\)
最优转移是\((x1,y1)\),存在一个不优的转移\((x2,y2)\),
根据题目条件,有\(i>x1>x2,s[i]>y1>y2,s[i]>i,y1>x1,y2>x2\)
一下个位置至少是\((i+1,s[i]+i)\),然后把斜率的式子写一写发现\((x1,y1)\)仍然更优。
现在可以做到\(O(nkp)\),但是这样的复杂度远远不够。
继续挖掘性质。
发现有一个条件我们还没有怎么使用,即所有\(h_i\)互不相等。
那么我们可以得到一个条件:每次转移的区间长度不会大于上一次转移的区间长度。
感性的证明就是越往后走高度越大,显然拿更少的位置来平分会更优。
或者可以假设一下区间的长度,然后计算一下结果就好了。
或者假如后面那个区间长度大于前面这个区间,那么把后面那个区间的最前面那个位置分给前面这一段一定更优。
还有一个奇怪的条件:长度大于\(1\)的区间个数不会超过\(O(log\frac{nh}{\Delta})\),其中\(\Delta=min(h_i-h_{i-1})\)
证明?我不会我不会,可以参考这里的证明
那么这样子,只需要\(dp\)大概\(14\)层就好啦。(参考征途或者序列分割之类的题目)
完整的代码戳这里
阉割版本。毕竟放个700行的代码翻都翻不完
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAX=8080;
Decimal ans;
int n,K,p,h[MAX],zy[MAX][15],s[MAX],tot;
int Q[MAX],H,T;
double f[MAX][15];
struct Node{double x,y;}q[MAX];
double Slope(Node a,Node b){return (a.y-b.y)/(a.x-b.x);}
Decimal Calc(int i,int j)
{
if(!j)return h[1];
return (Calc(zy[i][j],j-1)+s[i]-s[zy[i][j]])/(i-zy[i][j]+1);
}
int main()
{
n=read();K=read();p=read();h[tot=1]=read();
for(int i=2;i<=n;++i)
{
h[i]=read();
if(h[i]>h[1])h[++tot]=h[i];
}
n=tot;sort(&h[1],&h[n+1]);
for(int i=1;i<=n;++i)s[i]=s[i-1]+h[i];
K=min(K,n);
for(int i=1;i<=n;++i)f[i][0]=h[1];
int lim=min(K,14);
for(int j=1;j<=lim;++j)
{
Q[H=T=1]=1;
for(int i=1;i<=n;++i)q[i]=(Node){i-1,s[i]-f[i][j-1]};
for(int i=2;i<=n;++i)
{
Node u=(Node){i,s[i]};
while(H<T&&Slope(u,q[Q[H]])<Slope(u,q[Q[H+1]]))++H;
zy[i][j]=Q[H];f[i][j]=(s[i]-s[Q[H]]+f[Q[H]][j-1])/(i-Q[H]+1);
while(H<T&&Slope(q[Q[T]],q[Q[T-1]])>Slope(q[Q[T]],q[i]))--T;
Q[++T]=i;
}
}
int m=n-K+lim,pos;double mx=0;
for(int j=0;j<=lim;++j)
if(f[m][j]>mx)mx=f[m][j],pos=j;
ans=Calc(m,pos);
for(int i=m+1;i<=n;++i)ans=(ans+h[i])/2;
cout<<ans.to_string(p<<1)<<endl;
return 0;
}
【BZOJ4654】【NOI2016】国王饮水记(动态规划,斜率优化)的更多相关文章
- [UOJ#223][BZOJ4654][Noi2016]国王饮水记
[UOJ#223][BZOJ4654][Noi2016]国王饮水记 试题描述 跳蚤国有 n 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 1 号城市中.跳蚤国最大的问题就是饮水问题,由于首都中居住的跳 ...
- BZOJ4654 NOI2016国王饮水记(动态规划+三分)
有很多比较显然的性质.首先每个城市(除1外)至多被连通一次,否则没有意义.其次将城市按水位从大到小排序后,用以连通的城市集合是一段前缀,并且不应存在比1城市还小的.然后如果确定了选取的城市集合,每次选 ...
- luogu P1721 [NOI2016]国王饮水记 斜率优化dp 贪心 决策单调性
LINK:国王饮水记 看起来很不可做的样子. 但实际上还是需要先考虑贪心. 当k==1的时候 只有一次操作机会.显然可以把那些比第一个位置小的都给扔掉. 然后可以得知剩下序列中的最大值一定会被选择. ...
- uoj233/BZOJ4654/洛谷P1721 [Noi2016]国王饮水记 【dp + 斜率优化】
题目链接 uoj233 题解 下面不加证明地给出几个性质: 小于\(h[1]\)的城市一定是没用的 任何城市联通包含\(1\)且只和\(1\)联通一次 联通顺序从小到大最优 单个联通比多个一起联通要优 ...
- BZOJ4654/UOJ223 [Noi2016]国王饮水记
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- P1721 [NOI2016] 国王饮水记 题解
蒟蒻的第一篇黑题题解,求过. 题目链接 题意描述 这道题用简洁的话来说,就是: 给你 \(n\) 个数字,你可以让取其中任意若干个数字,每次操作,都会使所有取的数字变为取的数字的平均数,并且你最多只能 ...
- [Noi2016]国王饮水记
来自FallDream的博客,未经允许,请勿转载,谢谢. 跳蚤国有 n 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 1 号城市中.跳蚤国最大的问题就是饮水问题,由于首都中居住的跳蚤实在太多,跳蚤国王 ...
- 【学习笔记】动态规划—斜率优化DP(超详细)
[学习笔记]动态规划-斜率优化DP(超详细) [前言] 第一次写这么长的文章. 写完后感觉对斜优的理解又加深了一些. 斜优通常与决策单调性同时出现.可以说决策单调性是斜率优化的前提. 斜率优化 \(D ...
- *UOJ#223. 【NOI2016】国王饮水记
$n \leq 8000$的数列,问不超过$m \leq 1e9$次操作后第一个数字最大是多少.操作:选一些数,把他们变成他们的平均值.需要保留$p \leq 3000$位小数,提供了一个小数高精度库 ...
随机推荐
- 一个web应用的诞生(12)--再探首页
就要面对本章的一个难点了,说是难点可能仅仅对于我来说,毕竟我是一个js渣,既然首页打算使用动态加载的形式,那么与后台交互的方式就要进行选择,目前比较流行的为RESTful的形式,关于RESTful的文 ...
- Linux的常用命令笔记
这里使用的是centos操作系统 一.简单命令 (1)查看历史纪录: history (2)查看当前目录: pwd (3)查看系统当前时间和日期 date (4)查看当前登陆到系统的所有用户 who ...
- Selenide 阶段性总结介绍(UI自动化测试工具)
今天给大家介绍一个比较新的UI自动化测试工具-- Selenide.确实是比较新的,国内应该还没有多少人用它.在百度和google上你只能搜到一个中文帖子简单介绍了一下.如果你想用这个工具,不可避免的 ...
- java计算两个日期之间的天数,排除节假日和周末
如题所说,计算两个日期之前的天数,排除节假日和周末.这里天数的类型为double,因为该功能实现的是请假天数的计算,有请一上午假的为0.5天. 不够很坑的是每个日期都要查询数据库,感觉很浪费时间. 原 ...
- 算法工程师进化-NLP之主题模型
1 引言 主题模型是文本挖掘的重要工具,近年来在学术界和工业届都获得了非常多的关注.学术界的工作主要集中在建模层面,即提出各种各样的主题模型来适应不同的场景,因此缺乏指导主题模型在工业场景落地的资源和 ...
- ab命令做压测测试
1. 背景:互联网发达的今天,大大小小的网站如雨后春笋,不断出现,但是想要做出一个网站很简单,但是想要做好一个网站,非常非常难,首先:网站做好之后的功能怎么样这都是次要的,主要的是你的网站能承受怎么样 ...
- Scrum立会报告+燃尽图(Beta阶段第二周第四次)
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2412 项目地址:https://coding.net/u/wuyy694 ...
- 青岛 2016ICPC 区域现场赛题目
A. Relic Discovery B. Pocket Cube C. Pocky D. Lucky Coins E. Fibonacci F. Lambda Calculus G. Coding ...
- 团队作业05——测试与发布(alpha阶段)
测试 请根据团队项目中软件的需求文档.功能说明.系统设计和测试计划,写出软件的测试过程和测试结果,并回答下述问题. 在测试过程中总共发现了多少Bug?每个类别的Bug分别为多少个? 显示计算结果超过看 ...
- eclipse中jsp页面Invalid location of tag 解决办法分析小结
在jsp页面使用标签过程中有时候不注意规则的话,eclipse会提示一些错误,下面针对这些错误提出相应的解决办法: <form></form>标签 1. Invalid loc ...