【好题】思维+数学+二分+单调栈——NWERC 2019 Height Profile

可以很简单地发现,如果可以找到这样的两点,那么最优的情况一定是,两个点中至少有一个点在端点上。

对于每一个斜率k,将第i个节点减去k*i,形成新的图。在新的图上斜率大于等于0就是符合条件的。

我们可以枚举右端点。对于同一个右端点,如果点a比点b更靠近右端点并且点a不小于点b,那么点a就不需要考虑了,因为点b一定比它更好。所以从所有小于右端点的点中取出一个单调递减的数组,二分查找出最大的不大于右端点的点作为左端点。

尝试将左端点往左移动1km,将右端点往右移动1km,找出最大值。

 

/*
首先有结论,最长的段肯定是一端在端点上 
对于每个g,预处理:a[i]-i*g,这样只要a[j]-a[i]>=0,[i,j]就是满足要求的段
所以预处理出一个单调递减序列,对于每个a[i],在序列上找最右的比它大的即可 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define db double

int n,h[N],stk[N],top;
db g,a[N];

int main(){
    cin>>n;int q;cin>>q;
    for(int i=0;i<=n;i++)scanf("%d",&h[i]);
    while(q--){
        cin>>g;g*=10.0;
        for(int i=0;i<=n;i++)a[i]=h[i]-i*g;
        top=0;
        for(int i=1;i<=n;i++){
            if(top==0){stk[++top]=i;continue;}
            while(top && a[stk[top]]<=a[i])
                top--;
            stk[++top]=i;
        }
        db ans=0,last;
        for(int i=0;i<n;i++){
            if(i!=0 && a[i]>last)continue;
            else last=a[i];
            int L=1,R=top,mid,anss=-1;
            while(L<=R){
                mid=L+R>>1;
                if(stk[mid]<=i)
                    L=mid+1;
                else if(a[stk[mid]]>=a[i])
                    anss=stk[mid],L=mid+1;
                else R=mid-1;
            }
            if(i==0 && anss==n){ans=n;break;}
            if(anss!=-1){//[i,anss]这一段是合法的 
                db len1=0,len2=0;
                if(i!=0){
                    db L=0,R=1,mid;
                    while(R-L>=1e-7){
                        mid=(L+R)/2;
                        if(a[i]+mid*(a[i-1]-a[i])<=a[anss])
                            L=mid,len1=mid;
                        else R=mid;
                    }
                }
                if(anss!=n){
                    db L=0,R=1,mid;
                    while(R-L>=1e-7){
                        mid=(L+R)/2;
                        if(a[anss]+mid*(a[anss+1]-a[anss])>=a[i])
                            L=mid,len2=mid;
                        else R=mid;
                    }
                }
                ans=max(ans,1.0*anss-i+max(len1,len2));
            }
        }
        if(ans==0)
            puts("impossible");
        else printf("%.7lf\n",ans);
    }
}

 

posted on 2020-05-14 09:36  zsben  阅读(194)  评论(0编辑  收藏  举报

导航