• [IOI2014]holiday 假期 题解


    [IOI2014]holiday 假期 题解

    Problem

    ​ 给定一个序列,序列上每一个点有点权,给定一个出发点和一个花费,每次可以用1的花费在相邻两点间移动,也可以用1的花费获取当前点的点权的价值,每个点只可以被获取一次,求最大价值。

    Solution

    ​ 很容易发现,最优方法一定是先一直朝一个方向走,之后再看是否回头朝另一个方向走。

    ​ 那么我们可以把这个问题分成四个小问题,我们设\(f_{1,i},f_{2.i},f_{3,i},f_{4,i}\)分别表示花费为\(i\),向左/向右/向左后回到起点/向右后回到起点的最大价值,由它们组合得到答案。

    \(O(n^2logn)\)的DP是不难想到的,只要枚举最远到达的点,之后再用除去走完一遍路程的剩余的花费\(k\)在这段路程中选最大的\(k\)个价值即可,可以用主席树维护。

    ​ 考虑如何去优化这个DP,我们可以发现,每当有更多的可支配花费,最优的最远到达点只增不减,具有决策单调性,这个性质也比较明显。

    ​ 接下来,考虑如何实现,我们可以用决策单调性一个很常见的办法:分治来实现优化。具体而言,类似于整体二分一样。

    ​ 这道题细节很多,我写了一天,心态数次炸裂,最终终于完成,下面说说几个坑点:

    ​ 1.单调栈不好写这道题!我一开始写的是单调栈,最终感觉不好写,只有50pts,改换了分治。

    ​ 2.主席树注意判一下查询区间是否为空。

    ​ 3.\(m\)的范围不是1e5......

    ​ 4.最恶心的一点,注意起点的权值不要算到两次。

    Code

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    int n,m,k;
    int d[100005],t[100005],pos[300005],root[100005];
    LL Ans,f1[300005],f2[300005],f3[300005],f4[300005];//L,R,L->R,R->L
    
    struct Segment_Tree{
    
        int tot;
    
        LL sum[2000005];
    
        int seg[2000005],son[2000005][2];
    
        void insert(int &k,int p,int l,int r,int pos){
            k=++tot;
            seg[k]=seg[p]+1;
            son[k][0]=son[p][0];
            son[k][1]=son[p][1];
            sum[k]=sum[p]+t[pos];
            if(l==r)
                return;
            int mid=l+r>>1;
            if(pos<=mid)
                insert(son[k][0],son[p][0],l,mid+0,pos);
            else
                insert(son[k][1],son[p][1],mid+1,r,pos);
            return;
        }
    
        LL query(int k,int p,int l,int r,int kth){
            if(l==r)
                return 1LL*kth*t[l];
            LL res=0;
            int mid=l+r>>1;
            if(seg[son[k][1]]-seg[son[p][1]]>=kth)
                res+=query(son[k][1],son[p][1],mid+1,r,kth);
            else{
                res+=sum[son[k][1]]-sum[son[p][1]];
                res+=query(son[k][0],son[p][0],l,mid+0,kth-(seg[son[k][1]]-seg[son[p][1]]));
            }
            return res;
        }
    
        LL Query(int l,int r,int k){
            return l>r?0:query(root[r],root[l-1],1,n,min(k,r-l+1));
        }
    
    }T;
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
           if(ch=='-')f=-1;
           ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
           x=(x<<1)+(x<<3)+ch-'0';
           ch=getchar();
        }
        return x*f;
    }
    
    void solve1(int l,int r,int L,int R){
        if(l>r)
            return;
        int mid=l+r>>1;
        for(register int i=L;i<=R;++i){
            if(mid-(k-i<<0)<0)
                continue;
            LL res=T.Query(i,k,mid-(k-i<<0));
            if(!pos[mid]||res>f1[mid]){
                pos[mid]=i;
                f1[mid]=res;
            }
        }
        solve1(l,mid-1,pos[mid],R);
        solve1(mid+1,r,L,pos[mid]);
        return;
    }
    
    void solve2(int l,int r,int L,int R){
        if(l>r)
            return;
        int mid=l+r>>1;
        for(register int i=L;i<=R;++i){
            if(mid-(i-k<<0)<0)
                continue;
            LL res=T.Query(k,i,mid-(i-k<<0));
            if(!pos[mid]||res>f2[mid]){
                pos[mid]=i;
                f2[mid]=res;
            }
        }
        solve2(l,mid-1,L,pos[mid]);
        solve2(mid+1,r,pos[mid],R);
        return;
    }
    
    void solve3(int l,int r,int L,int R){
        if(l>r)
            return;
        int mid=l+r>>1;
        for(register int i=L;i<=R;++i){
            if(mid-(k-i<<1)<0)
                continue;
            LL res=T.Query(i,k-1,mid-(k-i<<1));
            if(!pos[mid]||res>f3[mid]){
                pos[mid]=i;
                f3[mid]=res;
            }
        }
        solve3(l,mid-1,pos[mid],R);
        solve3(mid+1,r,L,pos[mid]);
        return;
    }
    
    void solve4(int l,int r,int L,int R){
        if(l>r)
            return;
        int mid=l+r>>1;
        for(register int i=L;i<=R;++i){
            if(mid-(i-k<<1)<0)
                continue;
            LL res=T.Query(k+1,i,mid-(i-k<<1));
            if(!pos[mid]||res>f4[mid]){
                pos[mid]=i;
                f4[mid]=res;
            }
        }
        solve4(l,mid-1,L,pos[mid]);
        solve4(mid+1,r,pos[mid],R);
        return;
    }
    
    int main(){
        
        n=read();k=read();m=read();++k;
    
        for(register int i=1;i<=n;++i)
            d[i]=t[i]=read();
    
        sort(t+1,t+n+1);
    
        for(register int i=1;i<=n;++i){
            d[i]=lower_bound(t+1,t+n+1,d[i])-t;
            T.insert(root[i],root[i-1],1,n,d[i]);
        }
    
        memset(pos,0,sizeof pos);solve1(1,m,max(1,k-(m>>0)),k);
    
        memset(pos,0,sizeof pos);solve2(1,m,k,min(n,k+(m>>0)));
    
        memset(pos,0,sizeof pos);solve3(1,m,max(1,k-(m>>1)),k);
    
        memset(pos,0,sizeof pos);solve4(1,m,k,min(n,k+(m>>1)));
    
        for(register int i=0;i<=m;++i)
            Ans=max(Ans,max(f1[i]+f4[m-i],f2[i]+f3[m-i]));
    
        printf("%lld\n",Ans);
    
        return 0;
    }
    
  • 相关阅读:
    vue监听多个变量的方法
    Unicode与JavaScript详解
    两个数组合并的方法
    第13章 事件
    第12章 DOM2和DOM3
    IIS发布WebService的一些常见问题
    Openlayers修改矢量要素并且可捕捉
    Openlayers修改矢量要素
    openlayers画图形返回范围
    前台html与后台php通信(上传文件)
  • 原文地址:https://www.cnblogs.com/zjy123456/p/13714825.html
Copyright © 2020-2023  润新知