zoukankan      html  css  js  c++  java
  • Codeforces Round #622 (Div. 2)C2 Skyscrapers最大"尖"性矩形,思维||分治

    题:https://codeforces.com/contest/1313/problem/C2

    题意:给出n个数,分别代表第i个位置所能搭建的最大高度,问以哪一个位置的塔的高度为基准向左的每一个塔都小于等于临近右边的塔,向右每一个塔都大于等于临近的左边的塔所构建的高度之和是最大的,输出最大的高度之和;

    分析:我们设一个fir[i]数组,表示当前 i 位置向左能构造的最大高度和(就想阶梯一样,i位置是阶梯的最高处),sec[i]则是向右的;

       因为求出这俩个数组后,我们直接o(n)的访问fir[i]+sec[i]-a[i]找最大的既可找出能构造出最大面积和的位置;

       对于这个fir[]的求法,对于位置 i ,可以利用前面已经算得的结果,假设位置 j (j<i)很明显的fir[i]=fir[j]+(i-j)*a[i],因为再i~j间的高度都是大于a[i]的,fir[i]是取不到fir[i~j]间的部分面积的,所以把i~j高度降为和 i 位置的高度一样即可贪心地求最大,sec[]求法类似

    #include<bits/stdc++.h>
    using namespace std;
    const int M=5e5+5;
    typedef long long ll;
    ll a[M],pre[M],las[M],s[M],fir[M],sec[M],ans[M];
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,top=0;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        for(int i=1;i<=n;i++){
            while(top&&a[i]<a[s[top]])
                top--;
            pre[i]=s[top];
            s[++top]=i;
            fir[i]=fir[pre[i]]+1ll*(i-pre[i])*a[i];
        } 
        s[top=0]=n+1;
        for(int i=n;i>=1;i--){
            while(top&&a[i]<a[s[top]])
                top--;
            las[i]=s[top];
            s[++top]=i;
            sec[i]=sec[las[i]]+1ll*(las[i]-i)*a[i];
        }
        int pos=0;
        for(int i=1;i<=n;i++){
            if(fir[i]+sec[i]-a[i]>fir[pos]+sec[pos]-a[pos])
                pos=i;
        }
        for(int i=pos;i;i=pre[i])
            for(int j=i;j>pre[i];j--)
                ans[j]=a[i];
        for(int i=pos;i;i=las[i])
            for(int j=i;j<las[i];j++)
                ans[j]=a[i];
        for(int i=1;i<=n;i++)
            cout<<ans[i]<<' ';
        return 0;
    }
    View Code

    分治做法:

    分析:对于任意一段[l,r]的高度限制,假设a[i]是其中最小的高度,那么 要么是 i 的右边的高度全设为a[i],要么 i 的左边的高度全设为a[i]这俩种可能,那我们就分治下这些区间就行了;

       找最小的高度用线段树实现即可,也可用其他方法;

       复杂度分析,退化的情况我们分治的区间是[1,n],[1,n-1],[1,n-2]。。。这样n个区间,那么只要我们保证每个区间只是log级别的复杂度即可;

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int M=5e5+5;
    int n;
    struct node{
        ll val,id;
    }tr[M<<2];
    ll a[M],ans[M];
    void up(int root){
        if(tr[root<<1].val<=tr[root<<1|1].val){
            tr[root]=tr[root<<1];
        }
        else
            tr[root]=tr[root<<1|1];
    }
    void build(int root,int l,int r){
        if(l==r){
            tr[root].val=a[l];
            tr[root].id=l;
            return ;
        }
        int midd=(l+r)>>1;
        build(lson);
        build(rson);
        up(root);
    }
    node query(int L,int R,int root,int l,int r){
        if(L<=l&&r<=R){
            return tr[root];
        }
        node res;
        res.val=1e9+7;
        int midd=(l+r)>>1;
        if(L<=midd){
            node now=query(L,R,lson);
            if(now.val<res.val)
                res=now;
        }
        if(R>midd){
            node now=query(L,R,rson);
            if(now.val<res.val)
                res=now;
        }
        return res;
    }
    ll solve(int l,int r){
    //    cout<<l<<"!!"<<r<<endl;
        if(l>r)
            return 0ll;
        if(l==r){
            ans[l]=a[l];
            return a[l];
        }
        node now=query(l,r,1,1,n);
    //    cout<<now.id<<"!!"<<endl;
        ll lsum=solve(l,now.id-1);
        ll rsum=solve(now.id+1,r);
        if(lsum+now.val+1ll*now.val*(r-now.id)>1ll*now.val*(now.id-l)+now.val+rsum){
            for(int i=now.id;i<=r;i++)
                ans[i]=now.val;
            return lsum+now.val+now.val*(r-now.id);
        }
        else{
            for(int i=l;i<=now.id;i++)
                ans[i]=now.val;
            return now.val*(now.id-l)+now.val+rsum;
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        cin>>n;
        for(int i=0;i<=4*n;i++)
            tr[i].val=inf; 
        for(int i=1;i<=n;i++)
            cin>>a[i];
        build(1,1,n);
    
        solve(1,n);
        for(int i=1;i<=n;i++)
            cout<<ans[i]<<' ';
        return 0;
    }
    View Code
  • 相关阅读:
    html 上传图片前预览
    php获取当月天数及当月第一天及最后一天、上月第一天及最后一天实现方法
    php 计算 pdf文件页数
    php 获取半年内每个月的订单数量, 总价, 月份
    php 获取两个数组之间不同的值
    小程序支付功能
    关于nginx的Job for nginx.service failed because the control process exited with error code.错误
    linux 安装 Apollo
    MongoDB待续。。。
    ABP vNext...待续
  • 原文地址:https://www.cnblogs.com/starve/p/12355332.html
Copyright © 2011-2022 走看看