送礼物(二分答案+单调队列)

QUESTION:
JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物。萌萌的礼品店很神奇,所有出售的礼物都按照特定的顺序都排成一列,而且相邻的礼物之间有一种神秘的美感。于是,JYY决定从中挑选连续的一些礼物,但究竟选 哪些呢?假设礼品店一共有\(N\)件礼物排成一列,每件礼物都有它的美观度。排在第\(i\)(\(1\leq i \leq N\))个位置的礼物美观度为正整数\(A_i\)。JYY决定选出其中连续的一段,即编号为礼物\(i\),\(i+1\),....,\(j-1\),\(j\)的礼物。选出这些礼物的美观程度定义为:

(\(M(i,j)\)-\(m(i,j)\))\(\div\)\((j-i+k)\)

其中\(M\)\((\)\(i\)\(,\)\(j\)\()\)表示\(max\){\(A_i\),\(A_i+1\)\(,\)\(....\)\(A_j\)}
\(m\)\((\)\(i\)\(,\)\(j\)\()\)表示\(min\){\(A_i\),\(A_i+1\)\(,\)\(....\)\(A_j\)}\(,\)\(k\)为给定的正整数。

由于不能显得太小气,所以\(JYY\)\(所\)选礼物的件数最少为\(L\)件;同时,选得太多也不好拿,因此礼物最多选\(R\)件。\(JYY\)应该如何选择,才能得到最大的美观程度?由于礼物实在太多挑花眼,\(JYY\)打算把这个问题交给会编程的你。

输入格式

本题每个测试点有多组数据。
输入第一行包含一个正整数\(T\)(\(T \leq 10\)),表示有\(T\)组数据。
每组数据包含两行.
第一行四个非负整数\(N\),\(K\),\(L\),\(R\)(\(2\leq L\leq R\leq N\))。
第二行包含N个正整数,依次表示\(A_1,A_2....A_n\)(\(A_i\leq 10^8\))\(N,K\leq 50,000\)

输出格式

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

往下\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















继续

















W

















q

















t

















AK

















IOI!

















快到了


































Codefoces


































毁我人生!


































40M

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















30M

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















\(\bigvee\)

















20M\(\bigvee\)







\(\bigvee\)







\(\bigvee\)







\(\bigvee\)







\(\bigvee\)







\(\bigvee\)







\(\bigvee\)







\(\bigvee\)







\(\bigvee\)








10M









\(\bigvee\)








\(\bigvee\)








\(\bigvee\)








\(\bigvee\)








\(\bigvee\)








\(\bigvee\)








\(\bigvee\)








\(\bigvee\)








\(\bigvee\)








\(\bigvee\)

















XIBER!!!

解答:
作为比赛压轴,只有1人20分,其余10分,看了一下,还都是打表,也不知道老师为什么没有禁掉QWQ
PS:我们的AKDREAM同学这题由于每组数据没有重新初始化,送走了20分QAQ
但这道题不打表有一个明显的做法,枚举长度,从\(L\)开始枚,记录运算了多少次,然后超过4*\(10^7\)就退出(否则TLE),可以拿20分^_^
可以简单的发现,如果不考虑礼物个数的话,选出的区间应该两端为最大值与最小值(否则可以将不是最值的一端向里"缩",到最值为止,此时\(M(i,j)\),\(m(i,j)\)不变,\((j-i+k)\)变小,总体变大.
考虑到题目限制,需要先枚举长度为\(L\)的情况,用ST表或单调队列均可,这里选用单调队列.
之后可以采用二分答案mid,每一次a[L],a[R]一个最大,一个最小.,则max((A[i]?i?mid)?(A[j]?j?mid)?k?mid)与max((A[i]+i?mid)?(A[j]+j?mid)?k?mid)有一个大于等于0即可,原因很简单,不作说明.
其中A[i]?i?mid,A[i]+i?mid可以用单调队列维护.




上代码:

//JZC de 工业化代码

#include <bits/stdc++.h>
#define ll long long
#define MAX 50001
using namespace std;
ll t,n,k,l,r,head1,head2,tail1,tail2,head,tail;
ll q[MAX],q1[MAX],q2[MAX],a[MAX];
double cnt[50005],ans,Ans;
void I_P1(int i){
    while(head<=tail&&i>=q[head]+(r-l))head++;
    while(head<=tail&&cnt[q[tail]]>=cnt[i])tail--;
    q[++tail]=i;
}
void I_P2(int i){
    while(head<=tail&&q[head]-i>=r-l)head++;
    while(head<=tail&&cnt[q[tail]]>=cnt[i])tail--;
    q[++tail]=i;
}
bool check(double mid) {
    for(int i=1;i<=n;i++)cnt[i]=a[i]-mid*i;
    head=1;tail=0;Ans=-100000000.0;
    for(int i=1;i<=n-l;i++)I_P1(i),Ans=max(Ans,cnt[i+l]-cnt[q[head]]);
    for(int i=1;i<=n;i++)cnt[i]=a[i]+mid*i;
    head=1;tail=0;
    for(int i=n;i>l;i--)I_P2(i),Ans=max(Ans,cnt[i-l]-cnt[q[head]]);
    return Ans>=k*mid;
}
void Push(int i){//更新,将i更新至单调队列中
    while(head1<=tail1&&a[q1[tail1]]>=a[i])tail1--;
    q1[++tail1]=i;
    while(head2<=tail2&&a[q2[tail2]]<=a[i])tail2--;
    q2[++tail2]=i;
}
void Update(int i){//更新,将长度超标的弹出队列
    while(head1<=tail1&&i>=q1[head1]+l)head1++;
    while(head2<=tail2&&i>=q2[head2]+l)head2++;
}
int main() {
    cin>>t;
    while (t--) {
        cin>>n>>k>>l>>r;
        for(int i=1;i<=n;i++)cin>>a[i];
        head1=head2=1;
    tail1=tail2=0;
        //---计算长度为L的最大值---BEGIN
        for(int i=1;i<l;i++)Push(i);
        ans=-1e9;
        for (int i=l;i<=n;i++) {
            Update(i),Push(i);
            ans=max(ans,((double)(a[q2[head2]]-a[q1[head1]]))/(double)(l+k-1));
        }
        //---计算长度为L的最大值---END
        //---二分答案---BEGIN
        double l=0.0,r=10000.0;
        while(r>l+(1e-9)){
            double mid=(l+r)/2;
            if(check(mid))ans=max(ans,mid),l=mid;//更新
            else r=mid-(1e-7);
        }
        //---二分答案---END
        printf("%.4lf\n", ans);
    }
}

$ Tips$:
1.队列较多,千万不要搞混,血的教训QAQ
2.二分时每次需要-(1e-7),不然会玄学RE

原文地址:https://www.cnblogs.com/SZJZC/p/11407434.html

时间: 2024-11-09 16:54:42

送礼物(二分答案+单调队列)的相关文章

BZOJ 3316 JC loves Mkk 二分答案+单调队列

题目大意:给定一个环,要求在这个环上截取长度为偶数且在[L,R]区间内的一段,要求平均值最大 看到环果断倍增 看到平均值最大果断二分答案 看到长度[L,R]果断单调队列 对数组维护一个前缀和,对前缀和维护单调递增的单调队列 每扫过一个数sum[i],将sum[i-L]加入单调队列,再把距离i超过R的点删掉 长度为偶数?对奇数位置和偶数位置分别维护一个单调队列即可 每次找到大于0的子串之后记录一下分母再退出就行了 #include <cstdio> #include <cstring>

bzoj3316 JC loves Mkk 二分答案 单调队列

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3316 题意:给出一个环,求出长度在$L~R$之间任意偶数的一个序列,使得这个序列的平均值最大. 看到分数就知道这题不可做-- 好啦言归正传--这道题应该怎么做呢--直接上$PoPoQQQ$大爷的语录: 看到环果断倍增 看到平均值最大果断二分答案 看到长度[L,R]果断单调队列 没错就是这样--平均值这个东西其实就是要这么瞎搞--二分答案,然后给每个元素"咔嚓"一下去掉二分的值,之后

[bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)

偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1943  Solved: 1004[Submit][Status][Discuss] Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo

bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】

把模板串建一个广义SAM 然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串 二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i-1],f[j]+i-j(i-a[i]<=j<=i-L)},根据性质,i-a[i]是单调的(或者直接看a[i]的预处理过程也能看出来),所以这个dp可以用单调队列优化转移,最后判断是否f[n]>=L*0.9 #include<iostream> #include<cstdio

HDU 5089 Assignment(rmq+二分 或 单调队列)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 557    Accepted Submission(s): 280 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fr

codeforces 251A Points on Line(二分or单调队列)

Description Little Petya likes points a lot. Recently his mom has presented him n points lying on the line OX. Now Petya is wondering in how many ways he can choose three distinct points so that the distance between the two farthest of them doesn't e

【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1262  Solved: 643 Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整数,表示这篇作文的Lo 值. Sample Input 1 2 10110 000001110 1011001100 Sam

复习【dp+单调队列】

处理10W数据:二分答案+单调队列+dp 这题可以用二维Dp和一维Dp来做,虽然两者时间复杂度都是O(N2),但二维的无法被优化,一维的可以用单调队列将时间效率缩为O(N).因此构造Dp时优先采用纬度小的方案. 单调队列的核心模板见代码. ps:在一部分单调队列的题目中,队列各项的数值会同时变化.此时应用变量Plus做维护 #include <iostream> using namespace std; struct qnode { long tim, x; }; const long N=1

单调队列优化dp题目

附一链接,大多题型里面有,再附两题:https://blog.csdn.net/hjf1201/article/details/78729320 1.绿色通道 题目描述 Description <思远高考绿色通道>(Green Passage, GP)是唐山一中常用的练习册之一,其题量之大深受lsz等许多oiers的痛恨,其中又以数学绿色通道为最.2007年某月某日,soon-if (数学课代表),又一次宣布收这本作业,而lsz还一点也没有写-- 高二数学<绿色通道>总共有n道题目