JSOI 2015 送礼物

[BZOJ4476] [JSOI2015]送礼物

Description

JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物。
萌萌的礼品店很神奇,所有出售的礼物都按照特定的顺序都排成一列,而且相邻的礼物之间有一种神秘的美感。于是,JYY决定从中挑选连续的一些礼物,但究竟选哪些呢?
【问题描述】
假设礼品店一共有N件礼物排成一列,每件礼物都有它的美观度。排在第i1< =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

题解:

一道分数规划的题目。

RMQ问题我使用的ST表维护。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const double eps=1e-5;
const int maxn=100010;
const double INF=1e8;
int n,k,l,r;
int a[maxn],lg[maxn];
int f[18][maxn];
double f1[18][maxn],f2[18][maxn];
int read()
{
    int ret=0,f=1;  char gc=getchar();
    while(gc<'0'||gc>'9') {if(gc=='-')f=-f;   gc=getchar();}
    while(gc>='0'&&gc<='9')   ret=ret*10+gc-'0',gc=getchar();
    return ret*f;
}
int getsum(int l,int r)
{
    int k=lg[r-l+1];
    return min(f[k][l],f[k][r-(1<<k)+1]);
}
double getsum1(int l,int r)
{
    int k=lg[r-l+1];
    return min(f1[k][l],f1[k][r-(1<<k)+1]);
}
double getsum2(int l,int r)
{
    int k=lg[r-l+1];
    return min(f2[k][l],f2[k][r-(1<<k)+1]);
}
bool check(double mid)
{
    double ret=-INF;
    for(int i=1;i<=n;i++)    
    {
        f1[0][i]=a[i]-mid*i;
        f2[0][i]=a[i]+mid*i;
    }
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            f1[j][i]=min(f1[j-1][i],f1[j-1][i+(1<<j-1)]);
            f2[j][i]=min(f2[j-1][i],f2[j-1][i+(1<<j-1)]);
        }
    for(int i=1;i<=n;i++)
    {
        if(i>=l)
            ret=max(ret,f1[0][i]-getsum1(max(1,i-r+1),i-l+1));
        if(i<=n-l+1) 
            ret=max(ret,f2[0][i]-getsum2(i+l-1,min(n,i+r-1)));
    }
    for(int i=1;i<=n;i++)
        ret=max(ret,a[i]-getsum(max(1,i-l+1),min(n,i+l-1))-mid*(l-1));
    if(ret>=k*mid)
        return 1;
    else
        return 0;
}
int main()
{
    freopen("gift.in","r",stdin);
    freopen("gift.out","w",stdout);
    int T=read();
    while(T--)
    {
        n=read(),k=read(),l=read(),r=read();
        for(int i=1;i<=n;i++)   
            f[0][i]=a[i]=read();
        for(int i=2;i<=n;i++)    
            lg[i]=lg[i>>1]+1;
        for(int j=1;(1<<j)<=n;j++) 
            for(int i=1;i+(1<<j)-1<=n;i++) 
                f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]);
        double ll=0,rr=1e8,mid;
        while(rr-ll>eps)
        {
            mid=(ll+rr)/2;
            if(check(mid))  
                ll=mid;
            else    
                rr=mid;
        }
        printf("%.4lf\n",ll);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fusiwei/p/11352283.html