[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)最大,且[i,j]长度在区间[l,r]内。
M(i,j)表示[i,j]中的最大值,m(i,j)表示[i,j]中的最小值。
Ai< =10^8,N,K< = 50,000
分析
看到\(\frac{max(i,j)-min(i,j)}{j-i+k}\)的形式,我们敏感的想到01分数规划。考虑最终答案我们取的最大值和最小值在序列中的位置。
1.如果最大值和最小值在序列中的距离<L,那么用长度为L的区间包含它最优。因为如果区间更长的话,分子不变,分母会变大,不优。这种情况区间长度已经确定,可以不用01分数规划,直接用单调队列\(O(n)\)求即可。类似滑动窗口问题。
2.如果最大值和最小值在序列中的距离>=L,那么它们在区间的左右端点最优。同样如果区间更长的话,分子不变,分母会变大,不优。
按照01分数规划的套路,二分答案mid,判断当前答案是比mid大还是比mid小。如果比mid大,则有
\(|a_i-a_j| \geq mid(j-i+k)\)
(1)$ (a[i]+mid \times i)-(a[j]+mid \times j) \geq mid\times k $,
(区间左端点为最大值)只要暴力枚举i,再在i右侧满足区间长度条件的范围[i+L-1,i+R-1]内求一个\(a[j]+mid \times j\)最小的j即可
(2)$ (a_j-mid \times j)-(a_i-mid \times i) \geq mid \times k ,$
(区间右端点为最大值)只要暴力枚举j,再在j左侧满足区间长度条件的范围[i-L+1,i-R+1]内求一个\(a[j]+mid \times j\)最小的j即可
如果[i,j]内有比a[i]更大的a[k]怎么办?枚举到k的时候就会计入答案,且k为左端点的答案肯定比i优,会覆盖掉i为左端点的不合法情况
用ST表维护最小值即可。
时间复杂度\(O(n \log ^2 n)\),因为每次检查mid都要重新建一次ST表
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<deque>
#define INF 1e9
#define eps 1e-6
#define maxn 50000
#define maxlogn 20
using namespace std;
inline void qread(int &x){
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
int t;
int n,K,L,R;
int a[maxn+5];
//最大值最小值在两端的情况
//最大值最小值在区间两端的时候显然更优
// 01分数规划的套路,二分答案mid
//|a[i]-a[j]| >=mid(j-i+k)
//(1) (a[i]+mid*i)-(a[j]+mid*j)>=mid*k , 只要暴力枚举i,再在i右侧满足区间长度条件的范围内求一个值最小的j
//(2) (a[j]-mid*j)-(a[i]+mid*i)>=mid*k , 只要暴力枚举j,再在j左侧满足区间长度条件的范围内求一个值最小的j
//如果[i,j]内有比a[i]更大的a[k]怎么办?枚举到k的时候就会计入答案,且k为左端点的答案肯定比i优,会覆盖掉i为左端点的不合法情况
int log_2[maxn+5];
double st1[maxlogn+5][maxn+5];//维护a[i]+mid*i的最小值
double st2[maxlogn+5][maxn+5];//维护a[i]-mid*i的最小值
inline double max(double a,double b){
return a>b?a:b;
}
inline double min(double a,double b){
return a<b?a:b;
}
double query1(int l,int r){
int k=log_2[r-l+1];
return min(st1[k][l],st1[k][r-(1<<k)+1]);
}
double query2(int l,int r){
int k=log_2[r-l+1];
return min(st2[k][l],st2[k][r-(1<<k)+1]);
}
bool check(double mid){
for(int i=1;i<=n;i++) st1[0][i]=a[i]+mid*i;
for(int i=1;i<=n;i++) st2[0][i]=a[i]-mid*i;
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
st1[j][i]=min(st1[j-1][i],st1[j-1][i+(1<<(j-1))]);
st2[j][i]=min(st2[j-1][i],st2[j-1][i+(1<<(j-1))]);
}
}
double ans=-INF;
for(int i=1;i<=n;i++){
if(i+L-1<=n) ans=max(ans,a[i]+mid*i-query1(i+L-1,min(i+R-1,n)));
}
for(int i=1;i<=n;i++){//这里的i对应的是上面的j
if(i-L+1>=1) ans=max(ans,a[i]-mid*i-query2(max(i-R+1,1),i-L+1));
}
return ans>=mid*K;
}
//区间长度为L的时候,区间最大值不一定在左右端点,也可能成为最大答案
//直接长度为L的滑块窗口求解
double sp_solve(){
deque<int>qmax;
deque<int>qmin;
double ans=-INF;
for(int i=1;i<=n;i++){
while(!qmax.empty()&&qmax.front()<i-L+1) qmax.pop_front();
while(!qmin.empty()&&qmin.front()<i-L+1) qmin.pop_front();
while(!qmax.empty()&&a[qmax.back()]<a[i]) qmax.pop_back();
qmax.push_back(i);
while(!qmin.empty()&&a[qmin.back()]>a[i]) qmin.pop_back();
qmin.push_back(i);
ans=max(ans,1.0*(a[qmax.front()]-a[qmin.front()])/(L-1+K));
}
return ans;
}
double bin_search(){
double l=0,r=1000;
double mid;
double res=0;
// printf("db %d\n",check(0+eps)?1:0);
while(r-l>=eps){
mid=(l+r)/2;
if(check(mid)){
res=mid;
l=mid+eps;
}
else r=mid-eps;
}
return res;
}
int main(){
// freopen("1.in","r",stdin);
log_2[0]=-1;
for(int i=1;i<=maxn;i++) log_2[i]=log_2[i>>1]+1;
qread(t);
while(t--){
qread(n);
qread(K);
qread(L);
qread(R);
for(int i=1;i<=n;i++) qread(a[i]);
double ans1=sp_solve();
// printf("ans1=%.4f\n",ans1);
double ans2=bin_search();
double ans=max(ans1,ans2);
printf("%.4f\n",ans);
}
}
[BZOJ4476] [JSOI2015] 送礼物 (01分数规划+ST表)的更多相关文章
- P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表
P6087 [JSOI2015]送礼物 01分数规划+单调队列+ST表 题目背景 \(JYY\) 和 \(CX\) 的结婚纪念日即将到来,\(JYY\) 来到萌萌开的礼品店选购纪念礼物. 萌萌的礼品店 ...
- BZOJ4476 JSOI2015送礼物(分数规划+单调队列)
看到这个式子当然先二分答案.得max-min-(j-i+k)ans>=0. 显然max-min相同的情况下所选区间长度越短越好,所以max和min都应该取在边界.那么实际上我们根本不用管端点是否 ...
- BZOJ_4476_[Jsoi2015]送礼物_01分数规划+单调队列
BZOJ_4476_[Jsoi2015]送礼物_01分数规划+单调队列 Description JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物. 萌萌的礼品店很神奇,所有出售的 ...
- [BZOJ4476][JSOI2015]送礼物[分数规划+单调队列]
题意 题目链接 分析 分数规划之后可以得到式子:\(max-min-r*mid+l*mid\geq k*mid\) . 贪心选择,肯定区间的端点是极小或者极大值.特殊处理区间长度 \(\leq L\) ...
- bzoj4476 [Jsoi2015]送礼物
化简式子 $M>=m+ans*(r-l+k)$ 发现$M,m$确定时,总区间长度越小越好,于是假定右端点为最小值$M+ans*l>=m+ans*r+ans*k$, 右面都确定了,但最大值仍 ...
- 【BZOJ4476】[Jsoi2015]送礼物 分数规划+RMQ
[BZOJ4476][Jsoi2015]送礼物 Description JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物.萌萌的礼品店很神奇,所有出售的礼物都按照特定的顺序都排成 ...
- POJ3621Sightseeing Cows[01分数规划 spfa(dfs)负环 ]
Sightseeing Cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9703 Accepted: 3299 ...
- ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)
[题意]给出一个带权无向图,求割集,且割集的平均边权最小. [分析] 先尝试着用更一般的形式重新叙述本问题.设向量w表示边的权值,令向量c=(1, 1, 1, --, 1)表示选边的代价,于是原问题等 ...
- P2877 [USACO07JAN]牛校Cow School(01分数规划+决策单调性分治)
P2877 [USACO07JAN]牛校Cow School 01分数规划是啥(转) 决策单调性分治,可以解决(不限于)一些你知道要用斜率优化却不会写的问题 怎么证明?可以暴力打表 我们用$ask(l ...
随机推荐
- 自定义任务状态来操作FreeRTOS任务的挂起,恢复,删除
osThreadState osState2;//自定义一个线程的状态 osThreadState 系统枚举定义如下: typedef enum { osThreadRunning = 0x0, /* ...
- bzoj4819 [Sdoi2017]新生舞会 分数规划+最大费用最大流
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4819 题解 首先上面说, \[ C = \frac{\sum\limits_{i=1}^n a ...
- [转帖]ssh 远程执行命令
ssh 远程执行命令 https://www.cnblogs.com/youngerger/p/9104144.html SSH 是 Linux 下进行远程连接的基本工具,但是如果仅仅用它来登录那可是 ...
- 使用Spring.Net进行Webservice开发&发布遇到的问题
发布遇到的问题1: HTTP 错误 404.17 - Not Found 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理. 最终解决时IIS的设置情况: 1.应用程序池的高级设置中 启用32 ...
- UI Recorder安装与使用
现在的互联网公司,普遍在尝试并执行敏捷开发模式,那么必然要涉及到频繁的更新迭代,在每次更新迭代时,老功能的回归成为了老大难.当系统日益复杂,涉及到的回归点逐渐增多,UI自动化测试即使成本在大,也需要提 ...
- 【bzoj4136】[FJOI2015]带子串包含约束LCS问题
题目描述: 带有子串包含约束的最长公共子序列问题可以具体表述如下. 给定2个长度分别为n和m的序列X和Y,以及一个子串包含约束集S. S中共有k个字符串S={S1,S2,…,Sk},其中字符串Si的长 ...
- RedisTemplate访问Redis数据结构(二)——List
RedisTemplate使用ListOperations专门操作list列表.首先初始化spring工厂获得redisTemplate和opsForList private RedisTemplat ...
- 170905-MyBatis中的关系映射
===关系映射=== 参考文档复习:1对1,1对多,多对多 1.映射(多)对一.(一)对一的关联关系 1).使用列的别名 ①.若不关联数据表,则可以得到关联对象的id属性 ②.若还希望得到关联对象的其 ...
- 如何查看yum安装的程序包都放在哪些地方了?
yum安装, 是先下载下来, 然后安装, 用dnf代替yum后, 配置文件跟yum类似, 也是放在 /etc/dnf/ 目录下的, 也有dnf.conf 配置文件等 dnf list后面还可以跟参数: ...
- 查看linux显卡序列
1 lspci -vnn | grep VGA -A 12会输出显卡的硬件信息,第一行的第二个[]内是显卡的序列号2 在网站http://pci-ids.ucw.cz/read/PC/ 下方输入序列号 ...