zoukankan      html  css  js  c++  java
  • 洛谷P5892 [IOI2014] holiday 假期

    发现最优情况一定是一直向一个方向走或先走一段后再回来往回走一段。向左和向右是一样的,只需翻转就能转化为同一个问题了。

    考虑枚举走的区间,设走完整个区间后的剩余天数为 (k),那么对于该区间的最优答案一定是参观区间内权值前 (k) 大的城市,用主席树实现可以做到 (O(n^2 log n)) 的复杂度。

    发现随着左端点的变大,其对应的最优的右端点一定是不降的,也就是其具有决策单调性。因为之前的最优的右端点的城市一定是参观的,所以将右端点移出区间是不优的。

    像决策单调性的 (DP) 一样分治解决即可,复杂度为 (O(n log^2 n))

    #include<bits/stdc++.h>
    #define maxn 100010
    #define maxm 3000010
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,s,d,cnt,tot;
    ll ans;
    int rt[maxn],ls[maxm],rs[maxm];
    ll a[maxn],b[maxn],siz[maxm],sum[maxm];
    void insert(int l,int r,int pos,int &cur)
    {
        int x=++tot;
        ls[x]=ls[cur],rs[x]=rs[cur];
        siz[x]=siz[cur]+1,sum[x]=sum[cur]+b[pos],cur=x;
        if(l==r) return;
        if(pos<=mid) insert(l,mid,pos,ls[cur]);
        else insert(mid+1,r,pos,rs[cur]);
    }
    ll query(int l,int r,int k,int x,int y)
    {
        if(k<=0) return 0;
        if(k>siz[y]-siz[x]) return sum[y]-sum[x];
        if(l==r) return b[l]*k;
        if(k<=siz[rs[y]]-siz[rs[x]]) return query(mid+1,r,k,rs[x],rs[y]);
        return query(l,mid,k-siz[rs[y]]+siz[rs[x]],ls[x],ls[y])+sum[rs[y]]-sum[rs[x]];
    }
    ll calc(int l,int r)
    {
        return query(1,cnt,d-(2*(r-s)+s-l),rt[l-1],rt[r]);
    }
    void solve(int l,int r,int L,int R)
    {
        if(l>r) return;
        if(L==R)
        {
            for(int i=l;i<=r;++i) ans=max(ans,calc(i,L));
            return;
        }
        ll pos=L,mx=calc(mid,L);
        for(int i=L+1;i<=R;++i)
        {
            ll v=calc(mid,i);
            if(v>mx) mx=v,pos=i;
        }
        ans=max(ans,mx),solve(l,mid-1,L,pos),solve(mid+1,r,pos,R);
    }
    void clear()
    {
        for(int i=1;i<=n;++i) rt[i]=0;
        for(int i=1;i<=tot;++i) ls[i]=rs[i]=siz[i]=sum[i]=0;
        tot=0;
    }
    void work()
    {
        clear();
        for(int i=1;i<=n;++i) rt[i]=rt[i-1],insert(1,cnt,a[i],rt[i]);
        for(int i=1;i<=s;++i) ans=max(ans,calc(i,s));
        solve(1,s-1,s+1,n);
    }
    int main()
    {
        read(n),read(s),read(d),s++;
        for(int i=1;i<=n;++i) read(a[i]),b[i]=a[i];
        sort(b+1,b+n+1),cnt=unique(b+1,b+n+1)-b-1;
        for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
        work(),s=n-s+1,reverse(a+1,a+n+1),work(),printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    45_ansible概述、ansible基础 、ad-hoc、批量配置管理
    44_自定义镜像及仓库、持久化存储 、 Docker网络架构
    43_Docker概述、部署Docker、Docker镜像、Docker基本命令
    42_KVM简介、 Virsh管理 、 自定义虚拟机、虚拟设备管理
    41_iptables防火墙 filter表控制 扩展匹配 nat表典型应用
    40_系统审计 服务安全 Linux安全之打补丁
    39_加密与解密 AIDE入侵检测系统 扫描与抓包
    38_Linux基本防护 用户切换与提权 SSH访问控制 SELinux安全 、SSH访问控制 SELinux安全
    hdu5530
    bzoj3456
  • 原文地址:https://www.cnblogs.com/lhm-/p/13747174.html
Copyright © 2011-2022 走看看