• 【好题】思维+数学+二分+单调栈——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
    ",ans);
        }
    }
  • 相关阅读:
    【POJ】1204 Word Puzzles
    【POJ】1816 Wild Words
    【HDOJ】1247 Hat’s Words
    【HDOJ】2609 How many
    【POJ】1035 Spell checker
    【POJ】2418 Hardwood Species
    【POJ】1056 IMMEDIATE DECODABILITY
    数列有序!
    绝对值排序
    C语言合法标识符
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12886510.html
Copyright © 2020-2023  润新知