bzoj4476: [Jsoi2015]送礼物

考虑二分答案

对于一个区间一定是一边最大一边最小是最优的,还有不够补足L的情况,这个RMQ就好

枚举右端点是最大/最小,单调队列搞搞就完了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int _=1e2;
const int maxn=5e4+_;
const int mbit=30;
int n,K,L,R,a[maxn];

namespace ST
{
    int Bin[mbit],Log[maxn],mx[mbit][maxn],mn[mbit][maxn];
    void main()
    {
        Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2;
        Log[1]=0;for(int i=2;i<=n ;i++)Log[i]=Log[i/2]+1;
        
        for(int i=1;i<=n;i++)mx[0][i]=mn[0][i]=a[i];
        for(int j=1;Bin[j]<=n;j++)
            for(int i=1;i+Bin[j]-1<=n;i++)
                mx[j][i]=max(mx[j-1][i],mx[j-1][i+Bin[j-1]]),
                mn[j][i]=min(mn[j-1][i],mn[j-1][i+Bin[j-1]]);
    }
    int mxRMQ(int x,int y)
    {
        int k=Log[y-x+1];
        return max(mx[k][x],mx[k][y-Bin[k]+1]);
    }
    int mnRMQ(int x,int y)
    {
        int k=Log[y-x+1];
        return min(mn[k][x],mn[k][y-Bin[k]+1]);
    }
    double stu1()
    {
        double ans=0;
        for(int j=L;j<=n;j++)
        {
            ans=max(ans,(double)(mxRMQ(j-L+1,j)-mnRMQ(j-L+1,j))/(L-1+K));
        }
        return ans;
    }
}

namespace DD
{
    double em;
    namespace A
    {
        struct mnlist//单调减 
        {
            int head,tail,pos[maxn];
            void clear(){head=1,tail=0;}
            void push_back(int x)
            {
                while(head<=tail&&(double)-a[pos[tail]]<=(double)-a[x]+em*(x-pos[tail]))tail--;
                pos[++tail]=x;
            }
            void pop_top(int lim){while(head<=tail&&pos[head]<=lim)head++;}
            int top(){return pos[head];}
        }A;
        bool check()
        {
            A.clear();
            for(int j=L;j<=n;j++)
            {
                A.pop_top(j-R);//<=该决策点无效 
                A.push_back(j-L+1);
                
                int i=A.top();
                if((double)(a[j]-a[i])+em*i>=em*(K+j))return true;
            }
            return false;
        }
    }
    //~~~~~~~~~~~~~~A~~~~~~~~~~~~~~~~~~~~
    
    namespace B
    {
        struct mxlist
        {
            int head,tail,pos[maxn];
            void clear(){head=1,tail=0;}
            void push_back(int x)
            {
                while(head<=tail&&(double)a[pos[tail]]<=(double)a[x]+em*(x-pos[tail]))tail--;
                pos[++tail]=x;
            }
            void pop_top(int lim){while(head<=tail&&pos[head]<=lim)head++;}
            int top(){return pos[head];}
        }B;
        bool check()
        {
            B.clear();
            for(int j=L;j<=n;j++)
            {
                B.pop_top(j-R);//<=该决策点无效 
                B.push_back(j-L+1);
                
                int i=B.top();
                if((double)(a[i]-a[j])+em*i>=em*(K+j))return true;
            }    
            return false;
        }
    }
    //~~~~~~~~~~~~~~B~~~~~~~~~~~~~~~~~~~~
    
    bool check(){return A::check()|B::check();}
    double stu2()
    {
        double el=0,er=1e8;
        while(er-el>1e-5)
        {
            em=(el+er)/2;
            if(check())el=em;
            else er=em;
        }
        return el;
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&K,&L,&R);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        ST::main();
        printf("%.4lf\n",max(ST::stu1(),DD::stu2()));
    }
    
    return 0;
}

 

posted @ 2019-03-26 21:28  AKCqhzdy  阅读(171)  评论(0编辑  收藏  举报