• bzoj4476 [Jsoi2015]送礼物


    化简式子

    $M>=m+ans*(r-l+k)$

    发现$M,m$确定时,总区间长度越小越好,于是假定右端点为最小值$M+ans*l>=m+ans*r+ans*k$,

    右面都确定了,但最大值仍然有两种情况,一是最大值就在要求的区间内,二是在要求的区间右侧,

    对于第一种情况,直接把每个点的val扔进单调队列就可以了,第二种呢,因为要求区间长度最小,所以左端点即为$r-L+1$,单调队列维护$i-L+1~i$的最大值即可,

    左端点为最小值也一样。

    而且不需要判断在我们选的区间内是否有比$a[i]$更小的,因为那一定比这优,考虑过,

    所以每次check直接正反扫就好了。

    2017.11.7更新

    原程序被hack,因为如果只能全选的话,最小值又不在两边,就不会枚举到最优解,所以强行往两侧各添加n个0即可。

    代码已更正,可放心食用

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define N 150050
     7 #define eps 1e-6
     8 using namespace std;
     9 int n,l,r,k;
    10 int a[N];
    11 double val[N];
    12 int q1[N],q2[N],head1,head2,tail1,tail2;
    13 bool check(double x){
    14     head1=head2=1;
    15     tail1=tail2=0;
    16     for(int i=1;i<=2*n;i++){
    17         int pos=i-l+1;
    18         double now=-1000000000;
    19         if(pos>0){
    20             val[pos]=a[pos]+x*pos;
    21             while(head1<=tail1&&val[pos]>val[q1[tail1]])tail1--;
    22             q1[++tail1]=pos;
    23             while(head1<=tail1&&q1[head1]<=i-r)head1++;
    24             now=max(now,val[q1[head1]]);
    25         }
    26         while(head2<=tail2&&a[i]>a[q2[tail2]])tail2--;
    27         q2[++tail2]=i;
    28         while(head2<=tail2&&q2[head2]<=i-l)head2++;
    29         if(i>n&&pos>0){
    30             now=max(now,a[q2[head2]]+x*(i-l+1));
    31             if(now>=a[i]+x*(i+k))return 1;
    32         }
    33     }
    34     head1=head2=1;
    35     tail1=tail2=0;
    36     for(int i=3*n;i>=n+1;i--){
    37         int pos=i+l-1;
    38         double now=-1000000000;
    39         if(pos<=3*n){
    40             val[pos]=a[pos]-x*pos;
    41             while(head1<=tail1&&val[pos]>val[q1[tail1]])tail1--;
    42             q1[++tail1]=pos;
    43             while(head1<=tail1&&q1[head1]>=i+r)head1++;
    44             now=max(now,val[q1[head1]]);
    45         }
    46         while(head2<=tail2&&a[i]>a[q2[tail2]])tail2--;
    47         q2[++tail2]=i;
    48         while(head2<=tail2&&q2[head2]>=i+l)head2++;
    49         if(i<=2*n&&pos<=3*n){
    50             now=max(now,a[q2[head2]]-x*(i+l-1));
    51             if(now>=a[i]-x*(i-k))return 1;
    52         }
    53     }
    54     return 0;
    55 }
    56 int main(){
    57     int T;scanf("%d",&T);
    58     while(T--){
    59         scanf("%d%d%d%d",&n,&k,&l,&r);
    60         for(int i=n+1;i<=2*n;i++)scanf("%d",&a[i]);
    61         double L=0,R=1000,M;
    62         while(L+eps<R){
    63             M=(L+R)/2.0;
    64             if(check(M))L=M;
    65             else R=M;
    66         }
    67         printf("%0.4lf
    ",M);
    68     }
    69     return 0;
    70 }
    bzoj4476
  • 相关阅读:
    jmeter-获取数据库中的数据
    jmeter常见报错汇总
    学习目录
    Spring+Spring Security+JSTL实现的表单登陆的例子
    Spring+Spring Security+Maven 实现的一个Hello World例子
    第六章:位置匹配
    第五章:重复匹配
    第四章:使用元字符
    第三章:匹配一组字符
    第二章:匹配单个字符
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/7778339.html
Copyright © 2020-2023  润新知