• BZOJ_4476_[Jsoi2015]送礼物_01分数规划+单调队列


    BZOJ_4476_[Jsoi2015]送礼物_01分数规划+单调队列

    Description

    JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物。
    萌萌的礼品店很神奇,所有出售的礼物都按照特定的顺序都排成一列,而且相邻
    的礼物之间有一种神秘的美感。于是,JYY决定从中挑选连续的一些礼物,但究
    竟选哪些呢?
    【问题描述】
    假设礼品店一共有N件礼物排成一列,每件礼物都有它的美观度。排在第i
    1< =i< =N个位置的礼物美观度为正整数Ai,。JYY决定选出其中连续的一段,
    即编号为礼物i,i+1,…,j-1,j的礼物。选出这些礼物的美观程度定义为
    (M(i,j)-m(i,j))/(j-i+k)
    其中M(i,j)表示max{Ai,Ai+1....Aj},m(i,j)表示min{Ai,Ai+1....Aj},K为给定的正整数。
    由于不能显得太小气,所以JYY所选礼物的件数最少为L件;同时,选得太
    多也不好拿,因此礼物最多选R件。JYY应该如何选择,才能得到最大的美观程
    度?由于礼物实在太多挑花眼,JYY打算把这个问题交给会编程的你。

    Input

    本题每个测试点有多组数据。输入第一行包含一个正整数T(T< =10),表示
    有T组数据。
    每组数据包含两行,第一行四个非负整数N,K,L,R(2< =L< =R< =N。第二行
    包含N个正整数,依次表示A1,A2....An,(Ai< =10^8),N,K< = 50,000

    Output

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

    Sample Input

    1
    5 1 2 4
    1 2 3 4 5

    Sample Output

    0.7500

    可以发现一定是最大值和最小值都在两端时最优,但可能长度超出限制。
    答案可能由两部分组成:1.长度为L 2.最大值和最小值在两端。
    第一种情况直接维护个单调栈即可。
    第二种情况是个经典的01分数规划。
    二分答案x
    有$a[l]-a[r]>(r-l+k)*$x或$a[r]-a[l]>(r-l+k)*x$
    分别求$(a[l]+l*x)-(a[r]+r*x)$和$(a[l]-l*x)-(a[r]-r*x)$的最大值,用单调队列求即可,多个log就过不去了。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <stdlib.h>
    using namespace std;
    typedef double f2;
    #define eps 1e-7
    #define N 50050
    int n,a[N],K,L,R,Q1[N],l1,r1,Q2[N],l2,r2,Q3[N],l3,r3;
    f2 t[N];
    int main() {
    	int T;
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d%d%d%d",&n,&K,&L,&R);
    		int i;
    		for(i=1;i<=n;i++) scanf("%d",&a[i]);
    		l1=r1=l2=r2=0;
    		for(i=1;i<L;i++) {
    			while(l1<r1&&a[Q1[r1-1]]>=a[i]) r1--;
    			while(l2<r2&&a[Q2[r2-1]]<=a[i]) r2--;
    			Q1[r1++]=Q2[r2++]=i;
    		}
    		f2 ans1=-1000;
    		for(i=L;i<=n;i++) {
    			while(l1<r1&&i-Q1[l1]>=L) l1++;
    			while(l2<r2&&i-Q2[l2]>=L) l2++;
    			while(l1<r1&&a[Q1[r1-1]]>=a[i]) r1--;
    			while(l2<r2&&a[Q2[r2-1]]<=a[i]) r2--;
    			Q1[r1++]=Q2[r2++]=i;
    			ans1=max(ans1,1.0*(a[Q2[l2]]-a[Q1[l1]])/(L-1+K));
    		}
    		f2 l=0,r=1000;
    		while(r-l>eps) {
    			f2 mid=(l+r)/2;
    			f2 re=-100000;
    			l3=r3=0;
    			for(i=1;i<=n;i++) t[i]=a[i]-i*mid;
    			for(i=L+1;i<=n;i++) {
    				while(l3<r3&&i-Q3[l3]>=R) l3++;
    				while(l3<r3&&t[Q3[r3-1]]>=t[i-L]) r3--;
    				Q3[r3++]=i-L; re=max(re,t[i]-t[Q3[l3]]);
    			}
    			l3=r3=0;
    			for(i=1;i<=n;i++) t[i]=a[i]+i*mid;
    			for(i=n-L;i;i--) {
    				while(l3<r3&&Q3[l3]-i>=R) l3++;
    				while(l3<r3&&t[Q3[r3-1]]>=t[i+L]) r3--;
    				Q3[r3++]=i+L; re=max(re,t[i]-t[Q3[l3]]);
    			}
    			if(re>=mid*K) l=mid;
    			else r=mid;
    		}
    		//printf("%.4f
    ",ans1);
    		printf("%.4f
    ",max(ans1,l));
    	}
    }
    

     

  • 相关阅读:
    ruby 中super和super()的区别
    SeleniumWebdriver系列教程(2)————浏览器的简单操作
    ruby设计模式之合成模式1————基本的合成模式
    ruby中::究竟代表什么?
    手工测试用例就是自动化测试脚本——使用ruby 1.9新特性进行自动化脚本的编写
    如何使用bluecloth
    如何使用ruby去实例化1个autoit对象
    Ruby设计模式之策略模式二————更ruby些的策略模式
    SeleniumWebdriver系列教程(1)————快速开始
    Seleniumwebdriver系列教程(3)————如何执行一段js脚本
  • 原文地址:https://www.cnblogs.com/suika/p/9063306.html
Copyright © 2020-2023  润新知