P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表

题目背景

\(JYY\) 和 \(CX\) 的结婚纪念日即将到来,\(JYY\) 来到萌萌开的礼品店选购纪念礼物。

萌萌的礼品店很神奇,所有出售的礼物都按照特定的顺序都排成一列,而且相邻 的礼物之间有一种神秘的美感。于是,\(JYY\) 决定从中挑选连续的一些礼物,但究 竟选哪些呢?

题目描述

假设礼品店一共有 \(N\) 件礼物排成一列,每件礼物都有它的美观度。排在第 \(i\ (1\leqslant i\leqslant N)\) 个位置的礼物美观度为正整数 \(A_i\)​。\(JYY\) 决定选出其中连续的一段,即编号为 \(i,i+1,\cdots,j-1,j\) 的礼物。选出这些礼物的美观程度定义为

\[\frac{M(i,j)-m(i,j)}{j-i+K}
\]

其中 \(M(i,j)\) 表示 \(\max\{A_i,A_{i+1},\cdots,A_j\}\),\(m(i,j)\) 表示 \(\min\{A_i,A_{i+1},\cdots,A_j\}\),\(K\) 为给定的正整数。 由于不能显得太小气,所以 \(JYY\) 所选礼物的件数最少为 \(L\) 件;同时,选得太多也不好拿,因此礼物最多选 \(R\) 件。\(JYY\) 应该如何选择,才能得到最大的美观程度?由于礼物实在太多挑花眼,\(JYY\) 打算把这个问题交给会编程的你。

输入格式

本题每个测试点有多组数据。

输入第一行包含一个正整数 \(T\),表示有 \(T\) 组数据。

每组数据包含两行。第一行四个非负整数 \(N,K,L,R\)。第二行包含 \(N\) 个正整数,依次表示 \(A_1,A_2,\cdots,A_n\)​。

输出格式

输出 \(T\) 行,每行一个非负实数,依次对应每组数据的答案,数据保证答案不 会超过 \(10^3\)。输出四舍五入保留 \(4\) 位小数。

输入输出样例

输入

1

5 1 2 4

1 2 3 4 5

输出

0.7500

说明/提示

对于 \(100\%\) 的数据,\(T\leqslant 10,N,K\leqslant 5\times 10^4\),\(1\leqslant A_i\leqslant 10^8\),\(2\leqslant L,R\leqslant N\)。

分析

看到这一个式子,显然是 \(01\) 分数规划

但是一般的 \(01\) 分数规划都是上面一个求和公式比下面一个求和公式

而这一道题则是最大值减去最小值比区间长度加一个定值的形式

我们手玩一下会发现,一个区间的左右两端一定是该区间的最大值或最小值

因为如果你在最大值或者最小值的基础上继续扩展的话,分母会变大,结果会变小,肯定不利于我们求解

但是有可能最大值和最小值之间的元素个数小于最小的区间长度 \(l\) ,此时我们就必须向两边扩展

因此,我们分两种情况讨论:

\(1\) 、 区间的长度大于 \(l\)

此时,我们像正常的 \(01\) 分数规划一样二分枚举即可

我们设此时枚举到的价值为 \(mids\)

那么如果 \(\frac{M(i,j)-m(i,j)}{j-i+K} \geq mids\)

则有 \(\ M(i,j)-m(i,j) \geq mids \times (j-i+K)\)

根据之前推导的结论,两边的元素只能是最大值或者最小值

因此我们分类讨论

如果区间左边的元素大于区间右边的元素

则有 \(a[i]-a[j] \geq mids \times (j-i+K)\)

我们展开移一下项,就有

\(a[i]-a[j] \geq mids \times j- mids \times i +mids \times K\)

\(a[i]+i \times mids - a[j] - j \times mids \geq mids \times K\)

我们令 \(val[i]=a[i]+i \times mids\)

则就有 \(val[i]-val[j] \geq mids \times K\)

其中右边是一个常数

于是我们惊喜地发现这玩意可以用单调队列去搞一下

同理,如果区间左边的元素大于区间右边的元素

则有 \(a[j]-a[i] \geq mids \times (j-i+K)\)

\(a[j]-a[i] \geq mids \times j- mids \times i +mids \times K\)

\(a[j]- j \times mids - a[i] + i \times mids \geq mids \times K\)

我们令 \(val[i]=a[i]-i \times mids\)

则就有 \(val[j]-val[i] \geq mids \times K\)

也可以用单调队列去维护

\(2\) 、区间的长度等于 \(l\)

此时我们用 \(ST\) 表预处理出区间最大最小值

每次从左到右扫一边枚举左端点即可

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const double eqs=1e-6;
int zdz[maxn][20],zxz[maxn][20],a[maxn],n,k,l,r;
double ans=0;
void solve1(){
int cd=log2(l);
for(int i=1;i<=n-l+1;i++){
int j=i+l-1;
double mmax=max(zdz[i][cd],zdz[j-(1<<cd)+1][cd]);
double mmin=min(zxz[i][cd],zxz[j-(1<<cd)+1][cd]);
ans=max(ans,(mmax-mmin)/((double)l-1+(double)k));
}
}
//枚举区间等于l的情况,直接暴扫
int ql[maxn],qr[maxn],headl,headr,taill,tailr;
double val[maxn];
bool jud(double mids){
double res=mids*k;
memset(ql,0,sizeof(ql));
memset(qr,0,sizeof(qr));
headl=1,taill=0,headr=1,tailr=0;
for(int i=1;i<=n;i++){
val[i]=(double)a[i]-i*mids;
}
for(int i=l;i<=n;i++){
while(headl<=taill && i-ql[headl]+1>r) headl++;
if(headl<=taill && val[i]-val[ql[headl]]>=res) return 1;
while(headl<=taill && val[i-l+1]<=val[ql[headl]]) taill--;
ql[++taill]=i-l+1;
}
for(int i=1;i<=n;i++){
val[i]=(double)a[i]+i*mids;
}
for(int i=l;i<=n;i++){
while(headr<=tailr && i-qr[headr]+1>r) headr++;
if(headr<=tailr && val[qr[headr]]-val[i]>=res) return 1;
while(headr<=tailr && val[qr[tailr]]<=val[i-l+1]) tailr--;
qr[++tailr]=i-l+1;
}
return 0;
}
//单调队列分别搞一下
void solve2(){
double ml=0,mr=1000,mmids;
while(mr-ml>eqs){
mmids=(ml+mr)/2;
if(jud(mmids)) ml=mmids;
else mr=mmids;
}
ans=max(ans,ml);
}//01分数规划
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d",&n,&k,&l,&r);
ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<20;j++){
zxz[i][j]=0x3f3f3f3f,zdz[i][j]=-0x3f3f3f3f;
}
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
zxz[i][0]=a[i];
zdz[i][0]=a[i];
}
for(int j=1;j<=18;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
zxz[i][j]=min(zxz[i][j-1],zxz[i+(1<<(j-1))][j-1]);
zdz[i][j]=max(zdz[i][j-1],zdz[i+(1<<(j-1))][j-1]);
}
}
//ST表预处理
solve1();
//情况一
solve2();
//情况二
printf("%.4lf\n",ans);
}
return 0;
}

最新文章

  1. Linq的分页
  2. Git-Notes
  3. Java jstatd详解
  4. android studio gradle升级
  5. HTTP状态码(HTTP Status Code)及常用场景
  6. 深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题
  7. detailsview 样式小问题
  8. 51nod 1065 最小正子段和
  9. codeforces 682C Alyona and the Tree DFS
  10. Android笔记(三):View一些值得注意的地方
  11. JAVA笔记(一)super and this
  12. 理解Spring的Bean工厂
  13. Yii框架里用grid.CGridView调用pager扩展不显示最后一页按钮的解决
  14. 英语口语练习系列-C21-美式幽默
  15. 帆软报表(finereport) 折叠树
  16. router-link 绑定事件的方式
  17. 垂直水平居中总结css
  18. Java多线程-----创建线程的几种方式
  19. express + mongodb 搭建一个简易网站(一)
  20. Spring MVC入门(一)—— SpringMVC的执行流程与常用注解

热门文章

  1. ModuleNotFoundError: No module named &#39;phkit.pinyin&#39;
  2. 信不信?各种红包App最后都会整合游戏!App+游戏的变现模式分析
  3. Netty 学习笔记(3) ------ ChannelPipeline 和 ChannelHandler
  4. vscode 无法自动补全第三方库
  5. SUCTF2019-web Easyweb
  6. Flask框架(一):介绍与环境搭建
  7. python3 httpConnection——post请求
  8. 感性认识JWT
  9. 来自马铁大神的Spark10年回忆录
  10. Day03_WebCrawler(网络爬虫)