zoukankan      html  css  js  c++  java
  • BZOJ4367 IOI2014holiday假期(整体二分+主席树)

      显然最优策略是先走到一边要到达的最远城市,再换方向走到另一边要到达的最远城市(当然也可以直接停止),路上参观景点。

      先仅考虑求出只向左走,花费时间i时的最优解。如果能求出这个,类似的就可以求出所有情况。

      显然时间越长,应该往左边走的越远,参观的越多,但是这个最远城市的变化不一定连续,没法愉快地双指针或者直接二分答案。

      考虑类似整体二分的做法。设当前要求i在l~r,最远城市在x~y之间的最优解,对i=mid暴力求出最优解,然后递归处理两边。暴力需要进行nlog次,每次暴力需要求区间k大和,可以用主席树做到log,于是复杂度O(nlog2n)。

      注意起点处只能取一次。并且对mid求出的最远点如果有多解考虑清楚选哪一个。

      upd:才想起来这玩意就是决策单调性

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 100010
    #define ll long long
    int n,start,m,a[N],b[N],root[N],cnt,t;
    ll fl[N<<2],gl[N<<2],fr[N<<2],gr[N<<2];
    struct data{int l,r,x;ll sum;
    }tree[N*25];
    struct data2{ll x;int d;};
    void ins(int &k,int l,int r,int x) 
    {
        tree[++cnt]=tree[k],k=cnt;
        tree[k].x++,tree[k].sum+=b[x];
        if (l==r) return;
        int mid=l+r>>1;
        if (x<=mid) ins(tree[k].l,l,mid,x);
        else ins(tree[k].r,mid+1,r,x);
    }
    ll query(int x,int y,int l,int r,int k)
    {
        if (!y) return 0;
        if (l==r) return 1ll*min(tree[y].x-tree[x].x,k)*b[l];
        int mid=l+r>>1,t=tree[tree[y].r].x-tree[tree[x].r].x;
        if (t>=k) return query(tree[x].r,tree[y].r,mid+1,r,k);
        else return tree[tree[y].r].sum-tree[tree[x].r].sum+query(tree[x].l,tree[y].l,l,mid,k-t);
    }
    data2 calc(int tot,int x,int y,int op,int isr)
    {
        int mx=isr?x:y;ll ans=0;
        if (isr)
        {
            for (int i=x;i<=y;i++)
            if (tot>=abs(start-i)*(1+op))
            {
                ll v;
                if (i<start) v=query(root[i-1],root[start-op],1,t,tot-(start-i)*(1+op));
                else v=query(root[start-1+op],root[i],1,t,tot-(i-start)*(1+op));
                if (v>ans) ans=v,mx=i;
            }
        }
        else
        {
            for (int i=y;i>=x;i--)
            if (tot>=abs(start-i)*(1+op))
            {
                ll v;
                if (i<start) v=query(root[i-1],root[start-op],1,t,tot-(start-i)*(1+op));
                else v=query(root[start-1+op],root[i],1,t,tot-(i-start)*(1+op));
                if (v>ans) ans=v,mx=i;
            }
        }
        return (data2){ans,mx};
    }
    void solve1(int l,int r,int x,int y)
    {
        if (l>r||x>y) return;
        int mid=l+r>>1;data2 t=calc(mid,x,y,0,0);
        fl[mid]=t.x;
        solve1(l,mid-1,t.d,y);
        solve1(mid+1,r,x,t.d);
    }
    void solve2(int l,int r,int x,int y)
    {
        if (l>r||x>y) return;
        int mid=l+r>>1;data2 t=calc(mid,x,y,0,1);
        fr[mid]=t.x;
        solve2(l,mid-1,x,t.d);
        solve2(mid+1,r,t.d,y);
    }
    void solve3(int l,int r,int x,int y)
    {
        if (l>r||x>y) return;
        int mid=l+r>>1;data2 t=calc(mid,x,y,1,0);
        gl[mid]=t.x;
        solve3(l,mid-1,t.d,y);
        solve3(mid+1,r,x,t.d);
    }
    void solve4(int l,int r,int x,int y)
    {
        if (l>r||x>y) return;
        int mid=l+r>>1;data2 t=calc(mid,x,y,1,1);
        gr[mid]=t.x;
        solve4(l,mid-1,x,t.d);
        solve4(mid+1,r,t.d,y);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4367.in","r",stdin);
        freopen("bzoj4367.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),start=read()+1,m=read();
        for (int i=1;i<=n;i++) b[i]=a[i]=read();
        sort(b+1,b+n+1);
        t=unique(b+1,b+n+1)-b-1;
        for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+t+1,a[i])-b;
        for (int i=1;i<=n;i++) 
        {
            root[i]=root[i-1];
            ins(root[i],1,t,a[i]);
        }
        solve1(0,m,1,start);
        solve2(0,m,start,n);
        solve3(0,m,1,start-1);
        solve4(0,m,start+1,n);
        ll ans=0;
        for (int i=0;i<=m;i++)
        ans=max(ans,gl[i]+fr[m-i]),
        ans=max(ans,gr[i]+fl[m-i]);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    微信授权登录
    mpvue 试水的一天
    小程序请求接口统一封装到一个js文件中
    工作中vue项目前后端分离,调用后端本地接口出现跨域问题的完美解决
    百度小程序授权更好体验
    关于智能小程序网络请求封装
    vue 开发webapp 手机返回键 退出问题
    MySQL解决存入数据库和取出数据库时间格式问题
    关于小程序授权更好体验
    关于vue项目中在js中引入图片问题
  • 原文地址:https://www.cnblogs.com/Gloid/p/9865354.html
Copyright © 2011-2022 走看看