zoukankan      html  css  js  c++  java
  • 2018CCPC桂林 A-Array Merge 贪心

    2018CCPC桂林 A-Array Merge

    题意

    给定两个长度分别为(n)(m)的数组(A)(B),将这两个数组合并为一个数组(C),合并过程中原数组中的数字顺序不能改变,问(sum_{i=1}^{n+m}c_i cdot i)的最大值为多少。

    (n,mle 10^5)

    分析

    首先最大的数字一定是和前一个数字连续放的,那么我们可以将这两个数合并成一个块,这个块怎么和一个数字比较优先级呢,假设这个块中的两个数字为(a)(b),一个不相关的数字为(x),按(abx)的放置顺序的答案为(a+2b+3x),按(xab)的顺序放置答案为(x+2a+3b),这两种方案的答案差值为(2x-a-b),即我们只要比较(x)(frac{a+b}{2})的大小即可,将这个结论推广一下就是先放平均数较大的块最优,我们先将(a)中每个数字都当作一个大小为(1)的块,然后比较相邻的块的平均数大小,若后面的块的平均数大于前一个块,就合并两个块,直至无法合并,对(b)数组也分块,然后按平均数大小合并两个数组中的块并计算答案即可。

    Code

    #include<bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<ll,ll>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=1e5+10;
    const int inf=1e9;
    int T;
    int n,m;
    ll a[N],b[N];
    pii x[N],y[N];
    int k1,k2;
    int main(){
        ios::sync_with_stdio(false);
        //freopen("in","r",stdin);
        cin>>T;
        for(int cas=1;cas<=T;cas++){
            cin>>n>>m;
            rep(i,1,n) cin>>a[i];
            rep(i,1,m) cin>>b[i];
            k1=k2=0;
            for(int i=1;i<=n;i++){
                x[++k1]=mp(a[i],1);
                while(k1>1&&x[k1-1].fi*x[k1].se<x[k1].fi*x[k1-1].se){
                    x[k1-1]=mp(x[k1-1].fi+x[k1].fi,x[k1-1].se+x[k1].se);
                    --k1;
                }
            }
            for(int i=1;i<=m;i++){
                y[++k2]=mp(b[i],1);
                while(k2>1&&y[k2-1].fi*y[k2].se<y[k2].fi*y[k2-1].se){
                    y[k2-1]=mp(y[k2-1].fi+y[k2].fi,y[k2-1].se+y[k2].se);
                    --k2;
                }
            }
            int l=1,r=1,now=0,pos1=0,pos2=0;
            ll ans=0;
            while(l<=k1||r<=k2){
                if(l<=k1&&r<=k2){
                    if(x[l].fi*y[r].se<y[r].fi*x[l].se){
                        for(int i=1;i<=y[r].se;i++){
                            ++now;++pos2;
                            ans+=b[pos2]*now;
                        }
                        ++r;
                    }else{
                        for(int i=1;i<=x[l].se;i++){
                            ++now;++pos1;
                            ans+=a[pos1]*now;
                        }
                        ++l;               
                    }
                }else if(l<=k1){
                    for(int i=1;i<=x[l].se;i++){
                        ++now;++pos1;
                        ans+=a[pos1]*now;
                    }
                    ++l;
                }else{
                    for(int i=1;i<=y[r].se;i++){
                        ++now;++pos2;
                        ans+=b[pos2]*now;
                    }
                    ++r;                
                }
            }
            cout<<"Case "<<cas<<": "<<ans<<'
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    Linux 下杀毒可用工具 clamav
    Docker 添加环境系统文件配置
    Docker 空间大小设置
    Docker 扩容 容器空间大小
    bzoj 1088 DP
    bzoj 1096 斜率优化DP
    spoj p104 Matrix-Tree定理
    bzoj 1016 深搜
    WC后记
    bzoj 1301 后缀数组
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13995942.html
Copyright © 2011-2022 走看看