P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表
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\) 的礼物。选出这些礼物的美观程度定义为
\]
其中 \(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;
}
P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表的更多相关文章
- BZOJ_4476_[Jsoi2015]送礼物_01分数规划+单调队列
BZOJ_4476_[Jsoi2015]送礼物_01分数规划+单调队列 Description JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物. 萌萌的礼品店很神奇,所有出售的 ...
- BZOJ4476 JSOI2015送礼物(分数规划+单调队列)
看到这个式子当然先二分答案.得max-min-(j-i+k)ans>=0. 显然max-min相同的情况下所选区间长度越短越好,所以max和min都应该取在边界.那么实际上我们根本不用管端点是否 ...
- [BZOJ4476] [JSOI2015] 送礼物 (01分数规划+ST表)
[BZOJ4476] [JSOI2015] 送礼物 (01分数规划+ST表) 题面 给出n,k,l,r和序列a,要求从a中选一段连续的区间[i,j]出来,使得M(i,j)-m(i,j)/(j-i+k) ...
- 【BZOJ 3316】JC loves Mkk 01分数规划+单调队列
单调栈不断吞入数据维护最值,数据具有单调性但不保证位置为其排名,同时可以按照进入顺序找出临近较值单调队列队列两端均可删除数据但只有队末可以加入数据,仍然不断吞入数据但同时可以额外刨除一些不符合条件的数 ...
- BZOJ 5281--[Usaco2018 Open]Talent Show(分数规划&单调队列&DP)
5281: [Usaco2018 Open]Talent Show Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 79 Solved: 58[Sub ...
- [BZOJ4476][JSOI2015]送礼物[分数规划+单调队列]
题意 题目链接 分析 分数规划之后可以得到式子:\(max-min-r*mid+l*mid\geq k*mid\) . 贪心选择,肯定区间的端点是极小或者极大值.特殊处理区间长度 \(\leq L\) ...
- luogu P6087 [JSOI2015]送礼物 二分 单调队列 决策单调性
LINK:送礼物 原本想了一个 \(nlog^2\)的做法 然后由于线段树常数过大 T到30. 以为这道题卡\(log^2\)没想到真的有神仙写\(log^2\)的过了 是我常数大了 抱歉. 能过的\ ...
- 【BZOJ3316】JC loves Mkk 分数规划+单调队列
[BZOJ3316]JC loves Mkk Description Input 第1行,包含三个整数.n,L,R.第2行n个数,代表a[1..n]. Output 仅1行,表示询问答案.如果答案是整 ...
- POJ1821 单调队列//ST表 优化dp
http://poj.org/problem?id=1821 当我们在考虑内层循环j以及决策k的时候,我们可以把外层变量i看作定值,以此来优化dp状态转移方程. 题意 有n个工人准备铺m个连续的墙,每 ...
随机推荐
- 深入浅出Semaphore源码解析
Semaphore通过permits的值来限制线程访问临界资源的总数,属于有限制次数的共享锁,不支持重入. 前提条件 在理解Semaphore时需要具备一些基本的知识: 理解AQS的实现原理 之前有写 ...
- javascript原型:写一个合并后数组去掉同类项的方法
<!DOCTYPE html> <html> <head> <title>test013_Array_prototype_unique()</ti ...
- 7.CSMA协议
载波监听多路访问协议CSMA CS:载波侦听/监听,每一个站在发送数据之前要检测一下总线上是否有其他计算机在发送数据. MA:多点接入,表示许多计算机以多点接入的方式连接在一根总线上 协议思想:发送帧 ...
- 最小割&网络流应用
重要链接 基础部分链接 : 二分图 & 网络流初步 zzz大佬博客链接 : 网络流学习笔记 重点内容:最小割二元关系新解(lyd's ppt) 题目:网络流相关题目 lyd神犇课件链接 : 网 ...
- 算数组的长度cpp
今天被自己整傻了.... cpp int 型的数组就别想用strlen来求长度了,会报错的. (当然java 里直接用length就可以了...) 所以我建议用vector!!!!!!
- OpenFeign使用步骤
1. 新建 cloud-consumer-feign-order80 2. pom.xml <?xml version="1.0" encoding="UTF-8& ...
- macOS 遇到 svnadmin无法使用的情况
首先,我在网上查了很多资料,大多数开发者都是表明了mac内置svn,然后直接使用svnadmin来创建仓库,但是我用命令行敲入svnadmin却显示找不到svnadmin.最开始,有个资料说用whic ...
- 一款功能简约到可怜的SQL 客户端
你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...
- PHP 实例 - AJAX 与 XML-AJAX XML 实例
PHP 实例 - AJAX 与 XML AJAX 可用来与 XML 文件进行交互式通信. AJAX XML 实例 下面的实例将演示网页如何通过 AJAX 从 XML 文件读取信息: 实例 Sele ...
- Python File flush() 方法
概述 flush() 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入.高佣联盟 www.cgewang.com 一般情况下,文件关闭后会自动刷 ...