zoukankan      html  css  js  c++  java
  • CF777E Hanoi Factory

    Solution

    容易想到用 (f_i) 表示顶部圆环是 (i) 时的塔的最大高度。考虑如何转移,一个圆环 (i) 能放在另一个圆环 (j) 上,必有 (b_ileq b_j),所以容易想到按照 (b) 降序排序,那么 (f_i) 只需要从 (j (j<i)) 转移,就没有后效性。容易写出转移方程

    [f_i=max limits_{a_j<b_i} {f_j}+h_i quad jin[1,i) ]

    形象地说就是在前 (i-1) 个圆环中,找到 (a) 值小于一个值的所有 (f) 的最大值。显然可以离散化 (a)(b) 后用树状数组维护。

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    #define N 100007
    #define ll long long
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    struct Node{
        int a,b; ll h;
        bool operator <(const Node &x) const{
            return b!=x.b? b>x.b:a>x.a;
        }
    }t[N];
    
    int n,X[N<<1],sz;
    ll f[N],c[N<<1];
    
    inline int lowbit(int x){return -x&x;}
    inline void add(int x,ll v){while(x<=sz)c[x]=max(c[x],v),x+=lowbit(x);}
    inline ll query(int x){ll ret=0;while(x)ret=max(ret,c[x]),x-=lowbit(x);return ret;}
    
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
            t[i].a=read(),t[i].b=read(),t[i].h=read();
            X[(i<<1)-1]=t[i].a,X[i<<1]=t[i].b;
        }
        sort(t+1,t+1+n),sort(X+1,X+1+2*n);
        sz=unique(X+1,X+1+2*n)-(X+1);
        for(int i=1;i<=n;i++){
            t[i].a=lower_bound(X+1,X+1+sz,t[i].a)-X;
            t[i].b=lower_bound(X+1,X+1+sz,t[i].b)-X;
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            f[i]=query(t[i].b-1)+t[i].h;
            add(t[i].a,f[i]);
            ans=max(ans,f[i]);
        }
        printf("%lld",ans);
    }
    

    后面发现并不需要树状数组,观察这句话:

    f[i]=query(t[i].b-1)+t[i].h;
    

    因为 (b) 是单调不增的,所以决策集合一直在减小。对于三个圆环 (j)(i)(k),且有 (j<i<k),如果 (i) 不能从 (j) 转移过来,那么 (k) 也一定不能从 (j) 转移。所以我们可以维护这个决策集合,如果 (j) 不合法就直接删掉而不会对后面造成影响。再次观察转移方程,每次我们取了决策集合里面的最大值,之后又加上了一个正整数 (h),所以再把现在更新出来的 (f_i) 加入决策集合,(f_i) 就会成为决策集合里面的最大值,所以决策集合里的 (f) 也具有单调性,且是单增的。那么剩下的就可以用单调栈来维护了。单调栈复杂度 (O(n))

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    #define N 100007
    #define ll long long
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    struct Node{
        int a,b; ll h;
        bool operator <(const Node &x) const{
            return b!=x.b? b>x.b:a>x.a;
        }
    }t[N],sta[N];
    
    int n,top=0;
    ll f[N];
    
    inline ll max(ll x,ll y){return x>y? x:y;}
    int main(){
        n=read();
        for(int i=1;i<=n;i++)
            t[i].a=read(),t[i].b=read(),t[i].h=read();
        sort(t+1,t+1+n);
        ll ans=0;
        for(int i=1;i<=n;i++){
            while(top&&t[i].b<=sta[top].a) top--;
            sta[++top]=t[i];
            sta[top].h+=sta[top-1].h;
            ans=max(ans,sta[top].h);
        }
        printf("%lld",ans);
    }
    

    发现不需要离散化了,瓶颈在于排序。如果再把快排换成基数排序,那么总的时间复杂度大概就是 (O(n))

    Tips

    对于 (b_i=b_j),要按照 (a) 降序排序,因为顶部的内径越小越好,对后面的转移有正的影响。

  • 相关阅读:
    Linux top详解
    Could not load file or assembly 'Microsoft.Extensions.Hosting.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
    面试官最爱的 volatile 关键字,这些问题你都搞懂了没?
    HashMap面试题及答案(2020版)
    Linux 下安装Rider 和 Net core SDK
    [Dnc.Api.Throttle] 适用于. Net Core WebApi 接口限流框架
    开启谷歌浏览器多线程下载
    Ubuntu 20.04 安装 向日葵远程
    java
    docker镜像处理命令格式化工具 docker-command-format.html
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14125208.html
Copyright © 2011-2022 走看看